很多初学者在学习Python的面向对象部分时,不理解__init__()究竟是什么意思,我在这里做统一的回答。
创建一个类时,需要对类设置很多的实例字段(这里的“字段”实际上就是我们平时所说的“属性”。这里是为了区别属性与属性函数,故我引用了C#或Java中“字段”的说法),如下:
代码段_1
class Ball:
pass
ball = Ball()
ball.color = 'red'
ball.size = 'small'
ball.direction = 'up'
#注意,以上字段是实例的字段,而非类的字段
print(ball.color)
print(ball.size)
print(ball.direction)
我们看到,class Ball:里面的代码是空着的,直接在外面对实例字段进行赋值。
这样肯定略显繁琐。在面向对象领域,有一个专门的工具做这件事情,叫做“构造器”,也叫做“构造方法”,“构造函数”,如下:
代码段_2
class Ball:
def __init__(self,color,size,direction):
#构造方法的本质是个函数。既然是函数,就满足函数和函数参数的一切性质
self.color = color
self.size = size
self.direction = direction
ball = Ball('red','small','up')
print(ball.color)
print(ball.size)
print(ball.direction)
运行结果与代码段_1一致。
self是代码段_1中的ball的代名词。如果Ball类生成了很多实例,如ball_1,ball_2...那么,self就是ball、ball_1、ball_2的代名词。
self,英文意为“本身”。在Python中,即类本身创建的实例。
事实上,在Python的语法中,写“self”这个单词不是规定的,写任何单词都可以。例如C#或Java的程序员可以习惯用“this”,因为“this”是C#、Java规定的关键字。如果C#、Java程序员不太习惯Python的“self”,在写Python代码的时候,完全可以把“self”换成“this”。但是“self”是前辈们在这么多年使用Python中,约定俗成的“关键字”。为了Python代码的可读性和“业内习惯”,建议大家还是规规矩矩地写“self”。
注意,ball是ball,ball不是self,但是,self可以是ball。当然,self还可以是ball_1。所以,self包括了所有的实例。self和一个具体的实例是一种充分不必要的关系。
而且,方法参数里有了“self”,即说明该方法只能被类的实例所调用。而不能被类所调用。
当进行了类的实例化ball = Ball('red','small','up'),__init__()方法被添加了实际位置参数'red','small','up',然后自动运行。从某种意义上说('red','small','up')就是调用了__init__()方法的标志。所以,__init__()方法不需要额外使用实例去专门调用它。如:
ball.__init__('green','big','down')
没有必要再去用实例专门调用该方法。
但是,如果在必要的情况下,这种专门调用构造方法的语句还是需要的。
如:
class Ball:
def __init__(self,color,size,direction):
#构造方法的本质是个函数。既然是函数,就满足函数和函数参数的一切性质
self.color = color
self.size = size
self.direction = direction
ball = Ball('red','small','up')#第一次调用了__init__()方法
print(ball.color)
print(ball.size)
print(ball.direction)
ball.__init__('green','big','down')#第二次调用了__init__()方法
print(ball.color)
print(ball.size)
print(ball.direction)
====================================================================================
下面,我们尝试将实例字段转化为类字段:
class Ball:
pass
ball = Ball()
Ball.color = 'red'
Ball.size = 'small'
Ball.direction = 'up'
#现在,这些字段是类字段,而不是实例字段了
print(Ball.color)
print(Ball.size)
print(Ball.direction)
我们前面说了,self指的是类的所有实例。现在,我们所要赋值的不再是实例的字段,而是类的字段。那么,对于类的字段,我们要使用构造方法,该怎么做呢?可以这么做:
class Ball:
@classmethod
def __init__(cls,color,size,direction):
cls.color = color
cls.size = size
cls.direction = direction
ball = Ball('red','small','up')
print(Ball.color)
print(Ball.size)
print(Ball.direction)
很明显,我们把原来代码段的“self”换成了“cls”,还在方法前面加了一个修饰器“@classmethod”,代表这是一个类方法。
cls和self一样,不是Python规定的关键字,写任何关键字都可以。但是为了Python的可读性和业内规范,还是建议大家写“cls”。
============================================================================================
但是,在上一个代码段,我们有了Ball.color、Ball.szie、Ball.direction,那么ball.color、ball.szie、ball.direction是否存在呢?
答案是:存在的。返回的结果和Ball.color、Ball.szie、Ball.direction完全相同。