本文旨在澄清 python 里 __new__
vs __init__
和 cls
vs self
的概念。
很多初学者会困扰,python的“魔法函数” __new__
有啥用? 跟__init__
有啥区别? 为什么有的函数第一个输入变量是self
, 有的却是cls
? 这有啥区别?
好,废话不多说,先看一个例子:
class A(object):
def __new__(cls):
print("A.__new__ called")
return super(A, cls).__new__(cls)
def __init__(self):
print("A.__init__ called")
A()
print('finished')
运行结果为:
A.__new__ called
A.__init__ called
finished
为什么结果是这样呢?
因为:__new__
负责创建一个 object;之后 __init__
负责初始化这个 object。
有点绕是吧,再说具体点:
当A()
被 call 的时候,__new__
就自动执行了, 它创建了一个object(class的具体实例)并返回这个object,然后__init__
接手这个实例再接着执行。
每当__new__
创建并返回一个实例时,__init__
就接手这个实例然后执行,这个实例就是__init__
的第一个输入变量,永远不变的, 默认的self
。 说到这里,self
怎么来的应该很清楚了吧。
在平常应用中,我们定义某个class
时几乎不会去写它的__new__
方法,于是当我们call这个class
时,python会一直往上追溯到有__new__
的父辈class, 通常我们自定义的class都是object
的子类,所以执行的都是它的__new__
。object
的__new__
创建并返回的这个实例,是裸的。 然后我们的class
的__init__
再接手这个裸的实例去进一步加工,比如加上各种 self.xxx = xxx
, 或再执行一些别的code, 这个过程就是initialization。注意它和creation的区别,应该说的很清晰了吧。
那假如我们自己定义一个坏了的__new__
, 它没有返回一个实例,这事会发生什么呢?比如:
class A(object):
def __new__(cls):
print("A.__new__ called")
#return super(A, cls).__new__(cls)
def __init__(self):
print("A.__init__ called")
A()
运行一下,发现结果是:
A.__new__ called
finished
哈哈当然啦,__new__
没有返回一个创建好的实例,那么__init__
自然就执行不了了。 上头没有提供食材,厨子就揭不开锅做饭嘛。
这个时候有人会问了,为啥 __init__()
里面是 self
, 而__new__()
里面是cls
呢?
首先,我们澄清一下概念:
1、self
表示一个具体的实例(instance)
本身。(如果用了@staticmethod
,那么就可以无视这个self,因为staticmethod就可以理解成一个普通的函数)
2、cls
表示这个类(class)
本身。
OK, __init__()
里面的self
已经说清楚了,是刚刚__new__
出炉的一个创建好的实例(object / instance); 那__new__()
里面是cls
又是指哪个class呢?
简单说来:哪个class
召唤了__new__
, cls
就默认是哪个class
。
再看一个例子 (Singleton 单例模式的实现):
class Singleton(object):
def __new__(cls, *args, **kw):
if not hasattr(cls, '_instance'):
cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)
print('\n')
print('cls is ', cls)
print(type(cls._instance), cls._instance)
else:
print(' {} already exists'.format(cls._instance))
return cls._instance
class Bus(Singleton):
def sendData(self,data):
pass
class BusSon(Bus):
def sendData(self,data):
pass
if __name__ == '__main__':
busson1 = BusSon()
bus1 = Bus()
print('------------------------\n')
busson2 = BusSon()
bus2 = Bus()
print('------------------------\n')
Bus.__new__(BusSon)
Bus()
x = Singleton.__new__(Bus)
print(x)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。