TOC

在总结内置函数之前的一段和sean老师的聊天记录,希望可以帮助你理解下面的知识点:

类的内置方法(魔法方法)

凡是在类内部定义,以__开头__结尾的方法,都是类的内置方法,也称之为魔法方法

  • 类的内置方法,会在某种条件满足下自动触发

__new__()

__init__()触发前,自动触发。调用该类的时,内部会通过__new__()产生一个新对象。

class Demo:  # 在python3中所有的类默认继承object
    def __init__(self):
        print('此处是__init__方法的执行')

    def __new__(cls, *args, **kwargs):
        print('此处是__new__方法的执行')


Demo()

>>> 此处是__new__()方法的执行

我们发现此处虽然执行了__new__(),但并未执行__init__()的方法,让我们点进源码中看一下:

源码中介绍此方法会创建并返回一个新的对象,我们再看我们写的代码:

    这里相当于我们对Demo默认继承的父类object进行了`方法重写`,此时也是多态的一种表现形式,子类继承父类object,对object中的`__new__()`进行了方法重写,因此会执行子类Demo的`__new__()`方法。(在子类中找到该方法时,就不会再往父类中查找该方法。)

    当我们没有对object中的方法重写时,object会自动执行它内部的`__new__()`并调用`__init__()`,但是方法重写后,执行的是Demo中的`__new__()`,因此并不会自动帮我们调用`__init__()`。(我们Demo类中并没有写相关调用`__init__()`的方法。)
    解决方案:在末尾的return中,我们重新调用父类object中的`__new__`的方法:

此时父类中执行__new__()后自动帮我们调用__init__()所以此时可以打印出来__init__的信息。

__init__()

在类调用的时候触发,通过产生的对象自动调用__init__()

__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内置的类中帮我们做的)

那怎么解决这个问题呢?我们可以重写父类的方法后,对对象的字典进行赋值操作,如下:

为什么可以对对象的字典进行赋值?我们可以打印一下对象的属性字典中的内容:

我们也可以看一下类的字典:

__getattr__()

对象.属性获取属性时,若属性没有时触发。

返回是None,因此我们可以在方法中给他一个返回值:

__getattribute__()

在“对象.属性”获取属性时,若"属性没有"时触发。

__call__()

在调用对象对象 + ()时触发

__str__()

在打印对象时触发

  • 该方法必须要有一个“字符串”返回值

__getitem__()

在对象通过”对象[key]获取属性时触发

__setitem__()

在对象通过对象[key] = value设置属性时触发





12-15 02:49