python 特殊(魔法)方法

类和对象创建

__new__, 根据类创建对象,控制创建对象的过程,例如创建单例类。接收类对象,及构建对象的参数;返回创建的对象
__init__,对象属性的初始化。接收new魔法方法创建的对象,及构造对象的参数(与new魔法方法的对象参数一致),返回None
__del__,当对象被释放的时候要干什么事情,但是del关键字只会减少对象的引用,在对象的引用数量为0且触发了gc.colloction时才会释放对象并触发del方法
__init_subclass__初始化子类。在衍生类继承基类的时候触发。

class Base:
    def __init_subclass__(cls, name, *args):
        """
        初始化子类,可以接受子类继承过程中传递的参数
        """
        cls.name = name
        cls.x = {}
        
class A(Base, name=1):
    """
    继承的同时,可以传递位置参数
    """
    pass
    
A.x
print(A.name) # print 1

__class_getitem__ 可以对类取方括号subscribe

class A:
    def __class_getitem__(cls, item):
        print(item)
        return "value"
        
print(A['a'])  # print value

type hint就是通过该魔法方法实现的

__mro_entries__ 帮助继承的子类找到父类。有这个特殊方法的原因具体看PEP560

class A:
    def __mro_entries__(self, bases):
        """
        返回基类组成的元组
        """
        print(base)
        return (A, )
        
class B(A()):
    pass

__prepare__ 返回被继承类的属性或方法字典

class Meta(Type):
    @classmethod
    def __prepare__(self, name, bases, **kwargs):
        return {"name": "xiaoming"}
class A(metaclass=Meta):
    pass
print(A.name) # print xiaoming

__instancecheck__ 校验是否是同一个类或子类关系
__subclasscheck__校验是否是子类关系

class Meta(type):
    def __instancecheck__(self, instance):
        return True
    def __subclasscheck__(self, subclass):
        if subclass is int:
            return True
        else:
            return False

class A(metaclass=Meta):
    pass
    
o = A()
print(isinstance(123, A))    # True
print(issubclass(int, A))   # True

对象打印

__repr__ 打印对象的时候调用并返回该方法结果
__str__ 比repr更注重可读性,repr方法同时定义时优先触发str方法
__format__ 常用实例:print(f"15:b")打印15的2进制,print(f"15:x")打印15的16进制,

def __format__(self, spec):
    """
    判断输入的format spec是否是x,输出不同结果
    """
    if spec == 'x':
        return '十进制'
    else:
        return '<n>'

__bytes__ 如果对象由bytes(obj)调用的时候,触发该方法。或者类似bytes方法调用时候触发

比较运算

__eq__ 两个对象用==号触发,如果没有定义eq方法,会使用 is 来代替。如果定义了ne方法也可以用该方法触发,会将结果取反。
__ne__ 两个对象使用 !=号触发,如果定义了eq方法也可以用该方法触发,会将结果取反。
__gt__ 两个对象使用 > 或 < 号触发。但调用哪个对象的该方法不确定。
__lt__ 两个对象使用 > 或 < 号触发。但调用哪个对象的该方法不确定。一般调用左边类的魔法方法,但是如果右边的类是左边类的子类的时候会调用右边类(子类)的魔法方法。
__le__ 小于等于,解释器不会对该运算符做推理(不会用小于或者等于来代替)
__hash__ 返回整数,两个相等的对象必须返回同一个hash值,官方建议在hash函数中返回当前对象核心属性的tuple的hash结果
__bool__ 求bool场景下返回对象的布尔结果,例如 if obj 场景;

算数运算

__add__ 让类支持 + 操作
__radd__ 定义反过来运算的逻辑;所有运算符都有该魔法方法;
__iadd__ v1 += v2 ;inplace版本;返回self本身;所有运算符都有该魔法方法
__sub__ 让类支持 - 操作
__mul__ 让类支持 * 操作
__matmul__ 让类支持 @ 操作 矩阵乘法
__truediv__ 让类支持 / 操作
__floordiv__ 让类支持 // 操作
__mod__ 让类支持 % 操作,求余
__divmod__ 让类支持 divmod 操作,即拿到商又拿到余数
__pow__ 让类支持 ** 和pow操作。其中pow支持同时的mod操作,pow(a, b, mod=mod) ⇒ a ** b % mod有时该操作会更加快速
__lshift__ v1 << v2 位运算
__rshift__ v1 >> v2 位运算
__invert__ ~v1;一般用作位运算
__and__ v1 & v2;并不是重写了 and关键字
__or__ v1 | v2;并不是重写了 or 关键字
__xor__ v1 ^ v2
__pos__ +v1;返回新的值;在前面有正号时调用
__neg__ -v1;返回新值;在前面有负号时调用
__abs__ abs(v1) 时调用
__complex__ complex(v1) 返回类型必须为complex
__int__ int(v1)时调用 返回类型必须为int
__float__ float(v1)时调用 返回类型必须为float
__index__ 当把当前对象当成一个索引使用的时候希望得到的返回值;定义了index之后,int(v1),float(v1),complex(v1)都可以使用。

class Index:
    def __index__(self):
        return 1
index = Index()
lst = [1, 2, 3, 4, 5]
print(lst[index])  # print 2

__round__ 原函数逻辑四舍六入五看奇偶。通过该方法改变原方法的意思
__trunc__ 返回整数部分,忽略小数部分
__floor__ 向下取整,在操作负数的时候与trunc函数返回不同
__ceil__ 向上取整。操作正数时与trunc函数不同

print(math.trunc(-1.1))  # print -1.0
print(math.floor(-1.1))  # print -2.0
print(math.ceil(1.1)) # print 2.0

操作的两个对象不一定是同一个类型,只有在调用前一个对象的对应魔法方法时不失败即可。或在r方法中尝试调用成功也可以。

对象属性

__getattr__ 获取一个不存在的属性会调用该方法。接收属性名称,返回属性结果。当获取存在的属性时,不会调用该方法。常常在该方法中获取对象的其他存在的属性,且该调用方式获取的是存在的属性因此不会递归调用该方法,因此就不存在递归调用。
__getattribute__ 获取属性不论是否存在都会调用该方法。接收属性名称,返回结果。在想要返回默认值的时候一定要使用super().__getattribute__(name)如果使用getattr(self, name)会出现无限递归。因为getattr函数又会调用getattribute方法就这样一直递归下去。该方法很容易出现无限递归,例如

def __getattribute__(self, name):
    # 在获取counter属性的时候又调用了当前方法,此时出现自调用的无限递归
    self.counter += 1
    return super().__getattribute__(name)

__setattr__ 为对象的某个属性设置一个值,方法中常使用super().__setattr___(name, val) 来进行默认的操作。
__delattr__ 删除对象的属性时会调用。del obj.data 。同样使用super().__delattr__(name)来调用默认方式
__dir__ 获取当前属性的所有属性或方法

模拟

__call__ 将对象转换为callable;
__len__ 返回容器的长度;len(v1) ;如果该容器类没有定义bool方法,那么解释器尝试调用len方法,如果len返回长度为0,那么为False,如果长度不为0,那么为True;
__getitem__ 使用方括号读取值时调用该方法;支持切片操作
__setitem__ 使用方括号设置值的时候调用该方法;
__delitem__ 删除一个item时调用
__reversed__ 使用reversed(v1),调用该方法,默认对数据进行反转
__containes__ 使用in操作时候调用返回True或False。例如,2 in [2, 3, 4]
__iter__ 返回容器的iterator。使该对象成为可迭代对象;使对象支持for循环等
__missing__ 继承dict时,在获取不到dict中某个键时,调用该方法,获取返回值
__enter__ __exist__上下文管理器context;即使上下文报错,仍然可以成功调用exist方法;enter方法常返回上下文管理器本身self;

描述符

class D:
    """
    定义一个描述符
    """
    def __init__(self):
        self.val = 0
    
    def __set_name__(self, owner, name):
        """"
        在类定义中实例化当前类,就会触发该魔法方法;可以不是描述符
        
        :owner: 实例化该类所在的类
        :name: 当前对象所在类的属性名
        """"
        print(owner, name)

    def __get__(self, obj, owner=None):
        """
        在获取对象的描述符的时候会调用
        
        :self: 当前描述符对象
        :obj: 调用该描述符的对象,当前例子中为o, 
        :owner: 调用该描述符的类,当前例子中为A
        """
        return self.val
    
    def __set__(self, obj, value):
        """
        在为描述符赋值的时候触发
        
        :self: 当前描述符对象
        :obj: 调用该描述符的对象,当前例子中为o
        :value: 要赋予的新值
        """
        self.val = value
    
    def __delete__(self, obj):
        """
        删除描述符时调用
        """
        print("delete")
        
class A:
    d = D()
    
o = A()
o1 = A()
# 在获取对象的描述符的时候会调用该描述符的get魔法方法,且描述符是类属性级别的,所有对象共享该类的描述符
print(o.d)  # print 0
o.d = 2
print(o.d)  # print 2
print(o1.d)  # print 2
del o.d  # print delete

协程相关

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

岳大博

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值