Python类的内置成员方法 __init__, __new__ 和 __call__
__init__ 和 __new__
__init__
这个方法想必大家平常也用的很多,这个方法负责对象的初始化。
什么是初始化呢?就是对已经存在的东西赋若干个初始值。
所以我们可以知道当我们调用 __init__()
方法的时候,这个类已经被实例化了。
我们可以运行一下如下代码
class A():
def __new__(cls, *args, **kwargs):
print("run the new of A")
# return super().__new__(cls) 两句等价
return object.__new__(cls)
def __init__(self):
print("run the init of A")
a = A()
然后我们就会发现,一个类的创建遵循如下步骤
- 调用
__new__()
方法,如果自身没有定义,就去父类中查找,直到 object 类 __init__()
方法对实例化的对象本身进行初始化。
也就是实际上我们会先调用 __new__()
来实例化这个类,然后再去调用 __init__()
去对这个对象进行初始化。
然后我们看到 __new__()
传入了一个变量 cls
那么这个是什么呢?
答案是这个是这个类本身
不过我们可能会疑惑,为什么不是 self
?
答案是 self
代表的是实例对象本身,而不是类本身。
一般情况下,我们不会去重写 __new__
方法,除非你明确知道自己在做什么。但是在进行一些设计模式的编写的,比如单例模式和工厂模式。
然后我们就可以发现,既然我可以传入自己的类,那么我是不是也可以传入别的类,答案是肯定的。不过这样并不会调用任何人的 __init__()
函数。所以需要你自己手动对对象进行初始化,一般情况下也不会有什么作用。
需要注意的事情是 __new__
必须要有返回值,返回实例化出来的实例。
__call__
然后我们来看一下另一个内置成员方法 __call__
这个成员方法实际上就是让一个实例对象可以当作一个方法来调用
代码如下
class C:
def __init__(self, name):
self.name = name
def __call__(self, *args, **kwargs):
print("I'm {}".format(self.name))
c = C("Gensokyo_Alice")
c()
那么这个除了当作方法调用还有什么用呢,众所周知python还有一个方法叫做 hasattr
,不过它无法判断指定的名称是类方法还是类属性。
那么我们可以借助 __call__
来判断。
class C:
def __init__(self, name):
self.name = name
def __call__(self, *args, **kwargs):
print("I'm {}".format(self.name))
def dosth(self):
print("I'm {}".format(self.name))
c = C("Gensokyo_Alice")
if hasattr(c, "name"):
print(hasattr(c.name, "__call__"))
if hasattr(c, "dosth"):
print(hasattr(c.dosth, "__call__"))
因为类方法本质是一个可调用对象,所以实现了 __call__
方法。
而类属性则没有。
希望我们都有一个光明的未来