一、类对象和实例对象
在python对象模型中,类和通过类产生的实例是两种不同的对象类型:
- 类
类是实例工厂。类的属性提供了行为(数据以及函数),所有从类产生的实例都继承该类的属性 - 实例
实例对象是程序处理的实际对象:各自都有独立的命名空间,但同时继承了创建该实例的类中的变量名。实例的属性记录了每个实例自己的数据(例如:一个员工的社会保险账号)。 - 对比
类对象来自于class语句,而实例来自调用。每次调用一个类,你就会得到这个类的一个新的实例。
二、类对象提供默认行为
当我们执行class语句时,就会得到类对象。
- class 语句创建类对象并将其赋值给一个名称。就像函数的def语句,python的class语句也是可执行语句。当其执行时会产生新的类对象,并被赋值给class头部的名称。此外,就像def一样,class语句一般是在其所在文件被导入时执行的。
- class语句内的赋值语句会创建类的属性。就像模块文件一样,class语句内顶层的赋值语句(不是在嵌套的def之内)会产生类对象的属性。从技术的角度讲,class语句定义一个局部作用域,该作用域会变成类对象的属性命名空间,就像模块的全局作用域一样。
- 类属性提供了对象的状态和行为。类对象的属性记录了可由这个类所创建的所有实例共享的状态信息和行为。类内部的def语句会生成方法,方法可用于处理实例。
三、实例对象是具体的元素
当调用类对象时,我们得到了实例对象。
- 像函数那样调用类对象会创建新的实例对象。每次类被调用时,都会建立并返回新的实例对象。实例代表了程序领域中的具体元素。
- 每个实例对象继承了类的属性并获得了自己的命名空间。类所创建的实例对象是新的命名空间。它们一开始是空的,但是会继承创建该实例对象的类对象内的属性。
- 在方法内对self属性做赋值运算会产生每个实例自己的属性。在类的方法函数内,第一位参数(按惯例称为self)会引用当前处理的实例对象。对self的属性做赋值运算,会创建或修改实例内的数据,而不是类的数据。
四、类代码编写的细节
- class语句
class语句是复合语句,其缩进语句的主体一般出现在头部行下边。在头部行中,父类列在类名称之后的括号内,由逗号相隔。
class name(superclass):
attr = value
def method(self,...):
self.attr = value
在class语句内,任何赋值语句都会产生类属性,而且还有特殊名称方法重载运算符。例如,如果定义了名为_init_的构造函数就会在实例对象创建时调用。
- 属性
把简单的非函数的对象赋值给类属性,就会产生被所有实例共享的数据属性。
>>> class ShareData:
... spam = 42
...
>>> x = ShareData()
>>> y = ShareData()
>>> x.spam,y.spam
(42, 42)
由于名称spam是在class语句的顶层被赋值,因此会附加在这个类中,从而为所有的实例共享。我们可通过类名称修改它,或者是通过实例或者类引用它。
>>> SharedData.spam = 99
>>> ShareData.spam = 99
>>> x.spam,y.spam,ShareData.spam
(99, 99, 99)
我们通过使用实例来给spam赋值会发生什么?
>>> x.spam = 88
>>> x.spam,y.spam,ShareData.spam
(88, 99, 99)
对实例的属性进行赋值运算就会在改实例内创建或者修改名称,而不是在共享的类中。当附加在类上时,名称是共享的,当附加在实例上时,名称则是属于每个实例的数据,而不是共享的行为数据。
- 方法
方法是位于class语句的主体内,由def语句创建的函数对象。方法的工作方式与简单的函数完全一致,只是有一个重要的差异:方法的第一位参数总是接受方法调用的隐含主体,也就是当前的实例对象。python会自动把实例方法的调用映射为类的方法函数。
方法调用需要通过实例:
instance.method(args...)
这会被自动翻译成以下形式的类方法函数调用:
class.method(instance,args...)
- 示例
定义如下的类:
class NextClass:
def printer(self, text):
self.message = text
print(self.meessage)
printer引用了一个函数对象。因为它是在class语句的作用域中赋值的,所以会变成类对象的属性,这个类创建的每个实例都会继承这个属性。
>>> x = NextClass()
>>> x.printer('instance call')
instance call
>>> x.message
'instance call'
当对实例进行点号运算来调用它时,printer会先通过继承进行定位,然后它的self参数会自动赋值为实例对象(即x)。text参数会得到在调用时传入的字符串('instance call')。
类本身调用:
>>> NextClass.printer(x, 'class call')
class call
>>> x.message
'class call'
网友评论