__new__()
__init__()
__setattr__()
__getattr__()
__getattribute__()
__call__()
__str__()
__getitem__()
__setitem__()
在总结内置函数之前的一段和sean老师的聊天记录,希望可以帮助你理解下面的知识点:
类的内置方法(魔法方法)
凡是在类内部定义,以__开头__
结尾的方法,都是类的内置方法,也称之为魔法方法
- 类的内置方法,会在某种条件满足下自动触发
__new__()
在__init__()
触发前,自动触发。调用该类的时,内部会通过__new__()
产生一个新对象。
class Demo: # 在python3中所有的类默认继承object
def __init__(self):
print('此处是__init__方法的执行')
def __new__(cls, *args, **kwargs):
print('此处是__new__方法的执行')
Demo()
>>> 此处是__new__()方法的执行
我们发现此处虽然执行了__new__()
,但并未执行__init__()
的方法,让我们点进源码中看一下:
python3中所有的类默认继承object,点object进去可以看到
源码中介绍此方法会创建并返回一个新的对象,我们再看我们写的代码:
这里相当于我们对Demo默认继承的父类object进行了`方法重写`,此时也是多态的一种表现形式,子类继承父类object,对object中的`__new__()`进行了方法重写,因此会执行子类Demo的`__new__()`方法。(在子类中找到该方法时,就不会再往父类中查找该方法。)
当我们没有对object中的方法重写时,object会自动执行它内部的`__new__()`并调用`__init__()`,但是方法重写后,执行的是Demo中的`__new__()`,因此并不会自动帮我们调用`__init__()`。(我们Demo类中并没有写相关调用`__init__()`的方法。)
其实object也是python自定义的一个类:
解决方案:在末尾的return中,我们重新调用父类object中的`__new__`的方法:
此时父类中执行__new__()
后自动帮我们调用__init__()
所以此时可以打印出来__init__
的信息。
__init__()
在类调用的时候触发,通过产生的对象自动调用__init__()
。
注意:优先级没有
__new__
的高
__setattr__()
当object.属性 = values
,添加或修改属性时触发
class Demo:
def __init__(self):
print('此处是__init__方法的执行')
def __setattr__(self, key, value):
print('此处是__setattr__方法的执行')
print(key, value)
obj = Demo()
obj.x = 10
我们尝试打印一下看有没有添加上这个x的属性:
此时,虽然我们给obj对象添加了一个x的属性,但由于我们还是跟刚开始我和sean老师聊天中讲的一样,我们在类内部重写了默认继承的object的__setattr__()
的方法,因此不会去执行父类中的__setattr__()
的方法,因为默认查找的顺序是当前对象到当前子类,再到父类。我们也没在子类Demo中__setattr__()
方法里进行复制操作,因此并没有将值新增上去。
如果我们不在Demo中自己重写父类中的方法,就可以继承父类中的方法,因此我们直接,obj.x = 10
就可以将属性添加上了,效果如下:(这是python内置的类中帮我们做的)
那怎么解决这个问题呢?我们可以重写父类的方法后,对对象的字典进行赋值操作,如下:
为什么可以对对象的字典进行赋值?我们可以打印一下对象的属性字典中的内容:
不可以在方法内,利用self.key = value进行赋值,这样会重复调用
__setattr__()
进入死循环。(因为只要检测到对象.属性 = 值
的时候就会触发__setattr__()
)
我们也可以看一下类的字典:
__getattr__()
在对象.属性
获取属性时,若属性没有
时触发。
返回是None,因此我们可以在方法中给他一个返回值:
__getattribute__()
注意: 只要__getattr__ 与 getattribute 同时存在类的内部,只会触发__getattribute__。
在“对象.属性”获取属性时,若"属性没有"时触发。
__call__()
在调用对象对象 + ()
时触发
__str__()
在打印对象时触发
- 该方法必须要有一个“字符串”返回值
__getitem__()
在对象通过”对象[key]
获取属性时触发
__setitem__()
在对象通过对象[key] = value
设置属性时触发