请读者务必注意,本书讲述的是 Python 3 中类的创建方法,与 Python 2 相比,两个版本在定义类的时候稍有差别,如果看到了 Python 2 写的代码,注意区分。
打开你已经熟练使用的 IDE,用真正的 Python 程序实现8.1.2节中的“大侠”。
#coding:utf-8
"""
filename: superman.py
"""
class SuperMan: # (1)
''' # (2)
A class of superman
'''
def __init__(self, name): # (3)
self.name = name # (4)
self.gender = 1 # (5)
self.single = False
self.illness = False
def nine_negative_kungfu(self): # (6)
return "Ya! You have to die."
下面结合代码和图8-2-1,学习简单的、常见的类如何定义。
图8-2-1 简单类的结构
注释(1)逻辑行是类的头部,其组成部分是:
class
是定义类的关键词;SuperMan
是这个类的名称。通常,类名称中每个单词的首字母要大写,如果是多个单词组合,单词之间不插入其它符号。切记,“代码通常是给人看的”,类的名称也尽可能本着“望文生义”的原则命名。:
”。注意,与定义函数不同,这里没有圆括号。在8.5节会介绍什么时候用到圆括号。从注释(2)的逻辑行开始是类的代码块,依然是用四个空格的缩进表示代码块。
注释(2)的三引号以及后面的配对三引号,这之间是关于当前类的帮助文档,不是必须的。在通常的工程项目中,都要写,原因依然是“代码通常是给人看的”。
注释(3)和(6)定义了类的方法。它们都是由 def
这个关键词定义的,其实就是函数,只不过写在类里面罢了(8.4.1节会将类与方法给予比较)。习惯上,把写在类里面或者实例对象所具有的由 def
所定义的对象,叫做方法(Method)。
以类 SuperMan
中的方法 nine_negative_kungfu()
为例,其参数有特别的要求,第一个参数必须是 self
,而且它必须要有——至少要有一个名为self
的参数。另外,并非强制使用 self
参数名称,可以用别的名称,但使用 self
是惯例。这里所讲的规定和惯例,除了8.4.2和8.4.3节中所介绍的“类方法”和“静态方法”之外,对类的其他方法都适用——看来类的方法也不单纯。
既然方法和函数本质一样,那么方法的名称命名及其内部代码书写规范,就与函数一样了,此处不赘述,读者可以复习第7章关于函数的知识。
比较注释(3)和注释(6)两个逻辑行,所定义的方法虽然本质一样,但形式和命名还有差别。
注意方法名称“ __init__()
”的写法,是以双下划线开始和结尾。除了这个方法之外,在后续学习中,还会看到很多其他以双下划线开头和结尾的方法名称,Python 语言中将这些方法统称为特殊方法(Special Method),或者称为魔法方法(Magic Method,第9章中会介绍更多这类方法)。根据英文知识容易知晓,__init__()
方法的名称中的 “init” 来自单词 “initial” 。当用类创建实例的时候,首先访问这个方法(如果它存在的话),通过这个方法让实例具有其中所规定的属性。比如注释(4)的逻辑行:
self
表示实例化时创建的实例对象(8.2.2节会详细介绍);self.name
表示实例对象具有名称为name
的属性;self.name = name
表示实例对象的 name
属性(左侧的 name
)的值是实例化时参数 name
的实参(引用对象)。注意,符号 =
左侧所表示的实例属性的名称和右侧的参数(变量)名称不是非要求一样的。也可以使用注释(5)所示的那样,直接给实例属性赋值。由于 __init__()
方法是在创建实例开始就被调用,再结合“initial”这个单词,于是将这个方法称为“初始化方法”。
请读者注意,在有的中文资料中,把 __init__()
方法称为“构造方法”。本书作者认为这种命名易引起混乱,误导读者。因为在 Python 的类中,真正具有“构造”作用的方法是 __new__()
方法,不是 __init__()
。因此本书使用“初始化方法”与 __init__()
对应,而“构造方法”则是 __new__()
的中文名称(参阅第9章9.4节)。
还要提示读者注意,“初始化方法”的最后不要写 return 语句(如果非要写,就写 return None
)。
注释(6)所定义的是一个普通方法(相对“特殊方法”而言的“普通”,名称的命名上不用双下划线开头和结尾),除了参数列表中的 self
参数有前述规定和惯例之外,其他方面与第7章学过的函数没有差别。
创建了 SuperMan
类之后,就可以用它创建实例——形象地说,“类是实例的工厂”,用它可以塑造无限多个“超人”。
承接8.2.1所创建的 superman.py
文件中的 SuperMan
类,将它实例化,如下述代码:
#coding:utf-8
"""
filename: superman.py
"""
class SuperMan:
'''
A class of superman
'''
def __init__(self, name):
self.name = name
self.gender = 1
self.single = False
self.illness = False
def nine_negative_kungfu(self):
return "Ya! You have to die."
zhangsan = SuperMan("zhangsan") # (7)
print("superman's name is:", zhangsan.name) # (8)
print("superman is:(0-female, 1-male) ",zhangsan.gender) # (9)
result = zhangsan.nine_negative_kungfu() # (10)
print("If superman play nine negative kungfu, the result is:")
print(result)
程序中注释(7)的语句即依据 SuperMan
类创建一个实例,或说成“实例化”。所生成的实例是一个对象,或称为“实例对象”,并用变量 zhangsan
引用此对象。
在第7章7.3.1节曾借函数说明了对象后面紧跟圆括号的作用,可概括为“名称引用对象,圆括号才是执行”。对于类 SuperMan
而言,它也是一个对象——类也是对象,Python 中万物皆对象。例如:
>>> class Foo:
... def __init__(self):
... self.f = 'foo'
...
>>> Foo # (11)
<class '__main__.Foo'>
>>> type(Foo)
<class 'type'>
>>> id(Foo)
140693620290736
定义一个比较简单的类 Foo
——Foo
是类的名称。观察注释(11)及后续的操作,结合已学知识,可以总结出,与函数的名称引用函数对象雷同,类的名称也引用了类对象。
既然如此,如果要在后面增加一个圆括号,就应该表示“执行类”了。“类是实例的工厂”、“类是实例的蓝图”,执行类,就意味着产生实例。
>>> fo = Foo()
>>> fo
<__main__.Foo object at 0x7ff5c9622700>
>>> type(fo)
<class '__main__.Foo'>
由操作结果可知,Foo()
是一个实例对象。
再回到注释(7),执行类 SuperMan
,从而得到实例对象。注意,后面的圆括号中要有参数。这是因为 SuperMan
类的初始化方法的参数(形参)除了 self
之外,还有一个 name
,那么实例化(或者说“创建实例”)的时候,要为参数 name
传一个对象引用(实参)。
在实例化的时候,不需要给初始化方法中的 self
参数传对象引用。注释(7)执行之后,Python 解释器以“隐式传递”的方式,令 self
引用刚刚所创立的实例(参阅8.3.3节)。
在执行注释(7)即创建实例时,首先要调用类 SuperMan
里面所定义的初始化方法,执行其内部程序。本例中,创建了实例对象的一些属性并完成赋值。例如实例的 name
属性值是 'zhangsan'
,gender
属性值是 1
。注释(8)和(9)中,读取了所创建的实例 zhangsan
的两个属性 zhangsan.name
和 zhangsan.gender
的值。
注释(10)的 zhangsan.nine_negative_kungfu()
表示调用了实例 zhangsan
的 nine_negative_kungfu()
方法,调用方式和函数一样。但是要注意参数,在类 SuperMan
中,每个方法的第一参数是 self
,通过实例调用方法的时候,不需要在圆括号中为 self
提供对象引用,这是因为 Python 解释器以“隐式传递”的方式向 self
参数传了 zhangsan
这个实例对象的引用(严格说法是变量 zhangsan
引用的实例对象,参阅8.3.3节)。
很容易理解,以注释(7)的方式,通过修改形参 name
的值,还可以创建无数个 SuperMan
类的实例,这些实例之间的差别在于其 name
属性的值不同。此即“类是实例工厂”的含义,工厂可以根据一个生产模型生产出很多产品,例如汽车制造厂生产汽车。
构建简单的类之后,下面要对其重要组成部分——属性和方法——分别进行详细说明。