【Python】面向对象之类和对象
目录1面向过程和面向对象2.类和对象2.1类2.2对象3.定义类4.类的操作5.__init()__方法6.self6.1self作为实例传参6.2通过self在类中调用类中的实例属性和实例方法7.属性7.1类属性7.2实例属性8.方法8.1实例方法8.2类方法8.3静态方法8.4在类外定义方法8.5特殊方法9.动态添加属性与方法9.1动态给对象添加属性9.2动态给类添加属性9.3动态给实例添加方法9.4动态给类添加方法9.5动态删除属性与方法9.6_slots_限制实例属性与实例方法1面向过程和面向对象面向过程编程Procedural Programming和面向对象编程OOP是两种不同的编程范式它们在软件开发中都有广泛的应用。Python是一种混合型的语言既支持面向过程的编程也支持面向对象的编程。面向过程的编程是一种以过程为中心的编程方式主要关注解决问题的步骤并将这些步骤写成函数或方法。面向对象的编程是一种以对象为中心的编程方式主要关注在解决问题的过程中涉及哪些对象以及这些对象如何交互面向过程举例想象一下你要做一顿美味的晚餐。在面向过程编程的思维下你会把整个做饭的过程拆分成一系列的步骤。def buy(): print(去超市购买食材。) def wash(): print(清洗蔬菜。) def cut(): print(切菜。) def cook(): print(开始烹饪。) def serve(): print(上菜啦) buy() wash() cut() cook() serve()面就是一个典型的面向过程的程序我们把整个做饭的过程分解成了一个个函数每个函数完成一个特定的任务然后按照顺序依次调用这些函数就可以完成做晚餐的任务啦。这种方式非常直接适合一些简单的任务它注重的是程序的流程和步骤。但是呢当我们的程序变得越来越复杂会出现什么问题呢比如说我们现在想做不同类型的菜有些菜可能不需要洗菜有些菜可能不需要切菜或者你要同时做几道菜那我们的代码就会变得越来越长越来越乱而且上面的代码步骤是没有通用性的。面向对象举例先感受用面向对象的思想实现上面的做菜功能class Dish: def __init__(self, name): self.name name def prepare(self): pass class Salad(Dish): def prepare(self): print(f为 {self.name} 购买食材。) print(f清洗 {self.name} 的蔬菜。) print(f切 {self.name} 的蔬菜。) class Stew(Dish): def prepare(self): print(f为 {self.name} 购买食材。) print(f切 {self.name} 的肉。) print(f烹饪 {self.name}。) class Soup(Dish): def prepare(self): print(f为 {self.name} 购买食材。) print(f煮 {self.name}。) salad Salad(蔬菜沙拉) stew Stew(炖肉) soup Soup(西红柿鸡蛋汤) salad.prepare() stew.prepare() soup.prepare()在这里我们创建了一个 Dish 类它就像是一个菜的模板。然后我们创建了 Salad、Stew 和 Soup 这些子类它们都继承自 Dish 类。每个子类都有自己的 prepare 方法这个方法描述了如何准备这道菜。这样我们可以看到面向对象编程的优势啦 首先我们把相关的数据比如菜的名字和操作比如准备菜的过程都封装在了一个类里面这叫做 “封装”。而且不同类型的菜可以有自己独特的准备方法我们可以根据需要去修改或扩展这些方法而不会影响其他类。这就像是每个菜都有自己的制作过程。还有当我们想要添加新的菜品时我们只需要创建一个新的子类定义它自己的 prepare 方法就好不需要修改原来的代码。面向对象历史对象作为编程实体最早是于1960年代由Simula 67语言引入思维。Simula这一语言是奥利-约翰·达尔和克利斯登·奈加特在奥斯陆的挪威计算中心为模拟环境而设计的。据说他们是为了模拟船只而设计的这种语言并且对不同船只间属性的相互影响感兴趣。他们将不同的类型船只归纳为不同的类而每一个对象基于它的类可以定义它自己的属性和行为。这种办法是分析式程序的最早概念体现。在分析式程序中我们将真实世界的对象映射到抽象的对象这叫做“模拟”。Simula不仅引入了“类”的概念还应用了实例这一思想这可能是这些概念的最早应用。2.类和对象2.1类类描述了所创建的对象共同的属性是什么和方法能做什么属性和方法统称为类的成员。类是对大量对象共性的抽象类是创建对象的模板类是客观事物在人脑中的主观反映2.2对象在自然界中只要是客观存在的事物都是对象类是抽象的对象是类的实例Instance是具体的。一个对象有自己的状态属性、行为方法和唯一的标识本质上指内存中所创建的对象的地址。3.定义类语法class 类名: 类说明文档 类体类名一般使用大驼峰命名法。类体中可以包含类属性也叫类变量、方法、实例属性也叫实例变量等。案例定义一个人的类包含__init__()方法、eat()方法和drink()方法。class Person: 人的类 home earth def __init__(self): self.age 0 def eat(self): print(eating...) def drink(self): print(drinking...)4.类的操作类支持两种操作成员引用和实例化。成员引用语法类名.成员名案例class Person: 人的类 home earth def __init__(self): self.age 0 def eat(self): print(eating...) def drink(self): print(drinking...) home Person.home # 获取一个字符串 eat_function Person.eat # 获取一个函数对象 doc Person.__doc__ # 获取类的说明文档 print(home) # earth print(eat_function) # function Person.eat at 0x00000232C8230F40 print(doc) # 人的类实例化语法变量名 类名()案例class Person: 人的类 home earth def __init__(self): self.age 0 def eat(self): print(eating...) def drink(self): print(drinking...) p Person() # 创建一个对象 print(p.home) # earth print(p.age) # 0 p.eat() # eating... p.drink() # drinking...5.__init()__方法__init__() 是一个特殊的方法也被称作构造函数。__init__() 方法的主要作用是在创建类的对象时对对象的属性进行初始化。当你使用类名创建一个新的对象时Python 会自动调用 __init__() 方法并将新创建的对象作为第一个参数通常命名为 self传递给它。注意self这是一个约定俗成的参数名它代表类的实例对象本身。在方法内部通过 self 可以访问和修改对象的属性。__init__() 方法不是必需的。如果类中没有定义 __init__() 方法Python 会使用默认的构造函数该构造函数不执行任何操作。__init__() 方法只能返回 None不能返回其他值。如果尝试返回其他值会引发 TypeError 异常class Person: 人的类 home earth def __init__(self, name): self.name name p Person(张三) # 创建一个对象 print(p.name) # 张三6.self6.1self作为实例传参self代表类的实例自身。调用实例方法时实例对象会作为第一个参数被传入。因此我们调用p.eat()时就相当于调用了Person.eat(p)。class Person: 人的类 home earth def __init__(self, name): self.name name def eat(self): print(eating...) def drink(self): print(drinking...) p Person(张三) # 创建一个对象 p.eat() # eating... Person.eat(p) # eating...6.2通过self在类中调用类中的实例属性和实例方法class Person: 人的类 home earth def __init__(self, name): self.name name def eat(self): print(eating...) def drink(self): print(drinking...) def eat_and_drink(self): print(self.name) # 在类中调用name self.eat() # 在类中调用eat()方法 self.drink() # 在类中调用drink()方法 p Person(张三) # 创建一个对象 p.eat_and_drink()7.属性7.1类属性也叫类变量。在类中方法外定义的属性。通过类名.属性名或实例名.属性名访问class Person: 人的类 home earth # 定义类属性 print(Person.home) # 通过类名访问类属性 p1 Person() # 创建一个实例对象 print(p1.home) # 通过实例名访问类属性(如果实例没有覆盖这个类属性的值)通过类名.属性名添加与修改类属性class Person: 人的类 Person.home earth # 添加类属性 print(Person.home) # earth Person.home mars # 修改类属性 print(Person.home) # mars若使用实例名.属性名则会创建或修改实例属性因此不建议类属性和实例属性同名。class Person: 人的类 home earth p1 Person() p2 Person() print(Person.home) # earth print(p1.home) # earth print(p2.home) # earth print(通过 类名.属性名 修改 类属性) Person.home mars print(Person.home) # mars print(p1.home) # mars print(p2.home) # mars print(通过 实例名.属性名 会创建 实例属性) p1.home venus print(Person.home) # mars print(p1.home) # venus print(p2.home) # mars所有该类的实例共享同一个类属性class Person: 人的类 home earth # 定义类属性所有实例共享 p1 Person() # 创建一个实例对象 p2 Person() # 创建另一个实例对象 print(p1.home) # earth print(p2.home) # earth Person.home mars # 修改类属性 print(p1.home) # mars print(p2.home) # mars7.2实例属性也叫实例变量。在类__init__方法中定义的属性。通过self.属性名定义。通过实例名.属性名访问class Person: 人的类 def __init__(self, name, age): self.name name # 定义实例属性 self.age age # 定义实例属性 p1 Person(张三, 18) # 创建一个实例对象 print(p1.name, p1.age) # 张三 18 p2 Person(李四, 81) # 创建一个实例对象 print(p2.name, p2.age) # 李四 81 print(Person.name) # 报错通过实例名.属性名添加与修改实例属性class Person: 人的类 pass p1 Person() # 创建一个实例对象 p1.name 张三 # 添加实例属性 p1.age 18 # 添加实例属性 print(p1.name, p1.age) # 张三 18 p1.age 25 # 修改实例属性 print(p1.name, p1.age) # 张三 25每个实例独有一份实例属性class Person: 人的类 def __init__(self, name): self.name name # 定义实例属性 self.age 0 # 定义实例属性 p1 Person(张三) # 创建一个实例对象 print(p1.name, p1.age) # 张三 0 p1.age 18 # 修改p1的age属性 print(p1.name, p1.age) # 张三 18 p2 Person(李四) # 创建另一个实例对象 print(p2.name, p2.age) # 李四 08.方法Python的类中有三种方法实例方法、静态方法、类方法。8.1实例方法实例方法在类中定义第一个参数为self代表实例本身。实例方法只能被实例对象调用。可以访问实例属性、类属性、类方法。class Person: 人的类 home earth def __init__(self, name): self.name name def instance_method(self): print(self.name, self.home, Person.home) p Person(张三) p.instance_method() # 张三 earth earth此时p中没有home实例属性会去查找home类属性 Person.home venus # 修改类属性 p.home mars # 定义实例属性 p.instance_method() # 张三 mars venus8.2类方法类方法在类中通过classmethod定义第一个参数为cls代表类本身。类方法可以被类和实例对象调用。可以访问类属性。在不创建实例的情况下调用通过类名直接调用非常方便适合一些和类整体相关的操作。class Person: 人的类 home earth # 定义类属性 classmethod def class_method(cls): print(cls.home) Person.class_method() # 通过类调用类方法 p1 Person() # 创建一个实例对象 p1.class_method() # 通过实例对象调用类方法8.3静态方法静态方法在类中通过staticmethod定义不访问实例属性或类属性只依赖于传入的参数可以通过类名或实例调用但它不会访问类或实例的内部信息更像是一个工具函数只是为了方便组织代码把它放在了类里面。class Person: 人的类 home earth # 定义类属性 staticmethod def static_method(): print(static method) Person.static_method() # 通过类调用静态方法 p1 Person() # 创建一个实例对象 p1.static_method() # 通过实例对象调用静态方法8.4在类外定义方法并非必须在类定义中进行方法定义也可以将一个函数对象赋值给一个类内局部变量。# 在类外定义的函数 def f1(self, x, y): print(x y) class C: f f1 C().f(6, 13) # 48.5特殊方法方法名中有两个前缀下划线和两个后缀下划线的方法为特殊方法也叫魔法方法。上文提到的__init__()就是一个特殊方法。这些方法会在进行特定的操作时自动被调用。几个常见的特殊方法__new__()对象实例化时第一个调用的方法。__init__()类的初始化方法。__del__()对象的销毁器定义了当对象被垃圾回收时的行为。使用del xxx时不会主动调用__del__()除非此时引用计数0。__str__()定义了对类的实例调用str()时的行为。__repr__()定义对类的实例调用repr()时的行为。str()和repr()最主要的差别在于目标用户。repr()的作用是产生机器可读的输出大部分情况下其输出可以作为有效的Python代码而str()则产生人类可读的输出。__getattribute__()属性访问拦截器定义了属性被访问前的操作。9.动态添加属性与方法9.1动态给对象添加属性class Person: def __init__(self, nameNone): self.name name p Person(张三) print(p.name) # 张三 p.age 18 print(p.age) # 189.2动态给类添加属性class Person: def __init__(self, nameNone): self.name name p Person(张三) print(p.name) # 张三 Person.age 0 print(p.age) # 09.3动态给实例添加方法添加普通方法class Person: def __init__(self, nameNone): self.name name def eat(): print(吃饭) p Person(张三) p.eat eat p.eat() # 吃饭添加实例方法给对象添加的实例方法只绑定在当前对象上不对其他对象生效而且需要传入 self 参数。需要使用 types.MethodType(方法名实例对象) 来添加实例方法。import types class Person: def __init__(self, nameNone): self.name name def eat(self): print(f{self.name}在吃饭) p Person(张三) p.eat types.MethodType(eat, p) p.eat() # 张三在吃饭9.4动态给类添加方法给类添加的方法对它的所有对象都生效添加类方法需要传入 cls 参数添加静态方法则不需要。class Person: home earth def __init__(self, nameNone): self.name name # 定义类方法 classmethod def come_from(cls): print(f来自{cls.home}) # 定义静态方法 staticmethod def static_function(): print(static function) Person.come_from come_from Person.come_from() # 来自earth Person.static_function static_function Person.static_function() # static function9.5动态删除属性与方法del对象.属性名delattr(对象属性名)9.6_slots_限制实例属性与实例方法Python允许在定义类的时候定义一个特殊的__slots__变量来限制该类的实例能添加的属性。使用__slots__可以限制添加实例属性和实例方法但类属性、类方法和静态方法还可以添加。__slots__仅对当前类生效对其子类无效。import types class Person: __slots__ (name, age, eat) def __init__(self, nameNone): self.name name def eat(self): print(f{self.name}在吃饭) def drink(self): print(f{self.name}在喝水) p Person(张三) # 添加实例属性 p.age 10 print(p.age) # 10 # 添加实例方法 p.eat types.MethodType(eat, p) p.eat() # 张三在吃饭 # 添加实例属性 p.weight 100 # AttributeError: Person object has no attribute weight # 添加实例方法 p.drink types.MethodType(drink, p) # AttributeError: Person object has no attribute drink