Python 中的 dunder method

1. 基本的自定义

__new__ 与 __init__

# 3.0 后不继承任何类默认继承 Object, python 2.2 新增的新式继承方法


class MyClass:
    # __new__ 是一个 static method, args 是传入的参数 为 tuple类型, kwargs 为 dict 类型
    def __new__(cls, *args, **kwargs):
        print('new method', args, kwargs)
        # 不能用 MyClass() 会死循环
        return object.__new__(MyClass)

    def __init__(self, name, g):
        self.name = name
        self.g = g
        print('init method')


# 这里创建一根  MyClass 的对象, 首先会调用 __new__ 生产一个对象, 再调用 __init__ 进行一些初始化操作
# 自己没实现, 则会调用父类的 方法
o = MyClass("asdasd", "b")
# new method ('asdasd', 'b') {}
# init method
# 最终继承至 Object class
print(MyClass.mro())  # [<class '__main__.MyClass'>, <class 'object'>]

__del__

析构函数, 对象生命周期即将消失时调用的方法, 也有可能在 __del__方法里面对对象进行再一次的引用(不推荐), 这种做法叫做resurrection(耶稣复活), 这样析构函数就可能被调用多次, 目前 CPython 中的实现只会调用一次

__repr__ 和 __str__

都是美化对象的输出, 如果同时实现这两个方法, 会只输出__str__方法中返回的字符串

__format__

返回一个在进行占位的字符串, 有额外参数formatspec文档

    def __format__(self, format_spec):
        return "MyClassFormat"

__bytes__

使用bytes函数时会调用此方法, 返回 bytes string

比较运算

针对比较运算符的方法

object.__lt__(self, other)  # less than 
object.__le__(self, other)  # less equal 
object.__eq__(self, other)  # equal
object.__ne__(self, other)  # not equal
object.__gt__(self, other)  # greater than
object.__ge__(self, other)  # greater equal

__hash__

可以自定义哈希值

__bool__

bool() 函数所响应的方法, 返回一个 bool 值

2. 自定义属性访问

__getattr__

对于找不到对应的属性的, 就会响应的方法

print(o, o.ss)  # o.ss 并不存在

__getattribute__

访问属性的时候就会调用, 并且会覆盖掉 __getattr__

__setattr__

给属性赋值的时候触发

__delattr__

使用 del 关键字时会触发

__dir__

使用dir() 函数会触发, 必须返回一个队列

2.1 自定义模块的访问

__class__

只能是 types.ModuleType 的子类
目前不明白的这个属性的意义在哪(还太菜)

2.2 描述符

通过 实现__get____set____delete____set_name__(3.6 新增)来完成一个描述符类

class Desc:
    def __init__(self, name):
        self.name = name

    def __get__(self, instance, owner):
        print("__get__", instance, owner)

    def __set__(self, instance, value):
        print("__set__", instance, value)

    def __delete__(self, instance):
        print("__delete__", instance)

    def __set_name__(self, owner, name):
        print("__set_name__", owner, name)


class Td:
    c = Desc("cai")


t = Td()  # __set_name__ <class '__main__.Td'> c
t.c  # __get__ <__main__.Td object at 0x100ae56a0> <class '__main__.Td'>
t.c = "nihao"  # __set__ <__main__.Td object at 0x100ae56a0> nihao
t.c = "nibuhao"  # __set__ <__main__.Td object at 0x100ae56a0> nibuhao
del t.c  # __delete__ <__main__.Td object at 0x100ae56a0>

暂时没想到有什么应用场景

2.3 __slots__

限制 class 添加的属性名 __slots__ = ('name'), 就可以禁止 class 动态绑定属性 name

3 自定义类创建

__init_subclass__

继承之其他类的时候回触发的类方法, 可以自己添加参数

class Super:
    name = ""

    def __init_subclass__(cls, name, **kwargs):
        super.__init_subclass__(**kwargs)
        cls.name = name


class InitSub(Super, name="123"):
    pass


i = InitSub()
print(i, i.name)  # <__main__.InitSub object at 0x10a2be6a0> 123

3.1 Metaclasses

stackoverflow 上有大佬写了很详细的解答英文中文

4. 实例和子类的检查

__instancecheck__

使用 isinstance(instance, class) 会调用

__subclasscheck__

使用 issubclass(subclass, class) 会调用

5. 模仿可调用的对象

__call__

当一个对象被当成函数来调用时, 此方法会被调用

class Callable:
    def __call__(self, *args, **kwargs):
        print(args)  # ('as', 1, 3)


c = Callable()
c("as", 1, 3)

6. 模仿容器类型

__len__(self)

len() 时触发, 返回一个大于 0 的整数

__getitem__(self, key)

模仿队列的时候 key 只能是整数或者一个 slice 对象

__missing__(self, key)

dict 子类找不到对应的 key 则会触发此方法

__setitem__(self, key, value)

进行赋值操作, 仅在给旧的 key 赋值或者增加新的 key 时才有效

__delitem__(self, key)

移除某个 key 和 value

__iter__(self)

需要返回一个可迭代的对象iter()

__reversed__(self)

调用 reversed() 函数时会调用

__contains__(self, item)

使用测试操作符 innot in 时会触发此方法

7. 模仿可计算类型

object.__add__(self, other) 对应 +
object.__sub__(self, other) 对应 -
object.__mul__(self, other) 对应 *
object.__matmul__(self, other) 对应 @(矩阵乘法)
object.__truediv__(self, other) 对应 /(整数除法)
object.__floordiv__(self, other) 对应 //(浮点数除法)
object.__mod__(self, other) 对应 %
object.__divmod__(self, other) 对应 divmod()示例
object.__pow__(self, other[, modulo]) 对应 pow()幂计算
位操作
object.__lshift__(self, other) 对应 <<左移
object.__rshift__(self, other) 对应 >>右移
object.and(self, other) 对应 &
object.__xor__(self, other) 对应 ^异或
object.__or__(self, other) 对应 |
如果没实现的响应
object.__radd__(self, other)
object.__rsub__(self, other)
object.__rmul__(self, other)
object.__rmatmul__(self, other)
object.__rtruediv__(self, other)
object.__rfloordiv__(self, other)
object.__rmod__(self, other)
object.__rdivmod__(self, other)
object.__rpow__(self, other)
object.__rlshift__(self, other)
object.__rrshift__(self, other)
object.__rand__(self, other)
object.__rxor__(self, other)
object.__ror__(self, other)
还有一些就不一一列举了, 大多类似

参考:
https://docs.python.org/3/reference/datamodel.html#special-method-names

猜你喜欢

转载自blog.csdn.net/u010435828/article/details/80395906
今日推荐