类和实例的主要差异在于,类是一种产生实例的工厂。
类和模块的一个差异:内存中特定模块只有一个实例(所以我们得重载模块以取得其新代码),每个模块只有一个副本会导入某一个程序中(事实上,我们必须调用reload来更新单个模块对象,反映出来对该模块的修改,这就是原因之一),但是,对类而言,只要有需要,制作多少实例都可以。
Python把隐含的实例传进方法中的第一个特殊的参数,习惯上将其称为self
类连接至其超类的方式是,将超类列在类头部的括号内。其从左至右的顺序会决定树中的次序。
class C1(C2,C3):
如果你使用过C++或Java,就知道Python的self相当于this,但是Python中的self一定是明确写出来的,这样使属性的读取更为明显。
就像简单变量一样,类和实例属性并没有事先声明,而是在首次赋值时它的值才会存在。
从基本的角度来说,类其实就是由函数和其他变量名所构成的包,就像模块。然而,我们从类得到的自动属性继承搜索,支持了软件的高层次的定制,而这是我们通过模块和函数做不到的。
类对象提供默认行为执行class语句,就会得到类对象。以下是Python类主要特性:
class语句创建类对象并将其赋值给变量名。就像函数def语句,Python class语句也是可执行语句。执行时,会产生新的类对象,并将其赋值给class头部的变量名。此外,就像def应用,class语句一般是在其所在文件导入时执行的。
class语句内的复制语句会创建类的属性。就像模块文件一样,class语句内的顶层的赋值语句(不是在def之内)会产生类对象中的属性。从技术角度来讲,class语句的作用域会变成类对象的属性的命名空间,就像模块的全局作用域一样。执行class语句后,类的属性可由变量名点号运算获取object.name
类属性提供对象的状态和行为。类对象的属性记录状态信息和行为,可由这个类所创建的所有实例共享。位于类中的函数def语句会生成方法,方法将会处理实例。
实例对象是具体的元素
当调用类对象时,我们得到了实例对象。
像函数那样调用类对象会创建新的实例对象。每次类调用时,都会建立并返回新的实例对象。实例代表了程序领域中的具体元素。
每个实例对象继承类的属性并获得了自己的命名空间。由类所创建的实例对象是新命名空间。一开始是空的,但是会继承创建该实例的类对象内的属性。
在方法内对self属性做赋值运算会产生每个实例自己的属性。在类方法函数内,第一个参数(按惯例称为self)会引用正处理的实例对象。对self的属性做赋值运算,会创建或修改实例内的数据,而不是类的数据。
#!/usr/bin/env python
# coding=utf-8
class FirstClass:
def setdata(self, value):
self.data=value
def display(self):
print(self.data)
x=FirstClass()
y=FirstClass()
x.setdata("King Arthur")
y.setdata(3.14)
x.display()
y.display()
x.data="New value"
x.display()
在FirstClass的setdata函数中,传入的值会赋给self.data。在方法中,self(按惯例,这是最左侧参数的名称)会自动引用正在处理的实例(x或y),所以赋值语句会把值存储在实例的命名空间,而不是类的命名空间。
我们可以在类的内部或外部修改实例属性。在类内时,通过方法内对self进行赋值运算;而在类外时,则可以通过对实例对象进行赋值运算。虽然比较少见,通过在类方法函数外对变量名进行赋值运算,我们甚至可以在实例命名空间内产生全新的属性。
类通过继承进行定制
在Python中,实例从类中继承,而类继承与超类。
超类列在了类开头的括号中。
类从其超类中继承属性。
实例会继承所有可读取类的属性。
每个object.attribute都会开启新的独立搜索。Python会对每个属性取出表达式进行对类树的独立搜索。这包括在class语句外对实例和类的引用(例如,X.attr),以及在类方法函数内对self实例参数属性的引用。方法中的每个self.attr表达式都会开启对self及其上层的类的attr属性的搜索。
逻辑的修改是通过创建子类,而不是修改超类。在树中层次较低的子类中重新定义超类的变量名,子类就可以取代并定制所继承的行为。
#!/usr/bin/env python
# coding=utf-8
class FirstClass:
def setdata(self, value):
self.data=value
def display(self):
print(self.data)
class SecondClass(FirstClass):
def display(self):
print('Current value = "%s"' % self.data)
z=SecondClass()
z.setdata(42)
z.display()
有时候,我们把这种在树中较低处发生的重新定义的、取代属性的动作称为重载。
类是模块内的属性
如果FirstClass是卸载模块文件内,就可将其导入。单一模块文件内可以有一个以上的类,就像模块内其他语句,class语句会在导入时执行已定义的变量名,而这些变量名会变成独立的模块属性。
#!/usr/bin/env python
# coding=utf-8
from modulename import FirstClass
class SecondClass(FirstClass):
def display(self):
print('Current value="%s"' % self.data)
z=SecondClass()
z.setdata(42)
z.display()
实际上,Python中的通用惯例指出,类名应该以一个大写字母开头,以使得他们更为清晰。