类的魔法方法实质是 python 的内置方法,不需要主动调用。当我们在进行某种类的运算或操作时,python的解释器会自动调用相应的魔法方法。
类的魔法方法总是被双下划线所包围,一般格式为:“方法名”,它们功能强大,充满魔力。通过重载,魔术方法的实际功能可以根据实际需要进行更改。例如:init() 就是一个典型的魔法方法,当创建对象时会被系统调用,在定义类时,也可以根据需要设置它的实际功能。
一、基本魔法方法
x.init() ———— 创建对象后:MyObj = MyClass()
x.repr() ———— repr(x)
x.str() ———— str(x)
x.bytes() ———— bytes(x)
x.format(format_spec) ———— format(x, format_spec)
seq.iter() ———— iter(seq)
seq.next() ———— next(seq)
seq.reversed() ———— reversed(seq)
x.getattribute(‘my_property’) ———— x.my_property
x.getattr(‘my_property’) ———— x.my_property
x.setattr(‘my_property’, value) ———— 设置一个属性:x.my_property = value
x.delattr(‘my_property’) ———— del x.my_property
x.dir() ———— dir(x)
my_instance.call() ———— "调用"像函数一样的实例:my_instance()
s.len() ———— len(s)
s.contains(s) ———— 否包含特定的值:x in s
x.getitem(key) ———— x[key]
x.setitem(key, value) ———— 通过key来设置一个值:x[key] = value
x.delitem(key) ———— del x[key]
x.missing(nonexistent_key) ———— 为丢失的key提供默认值:x[nonexistent_key]
二、运算魔法方法
x.add(y)、x.radd(y) ———— x + y
x.sub(y)、x.rsub(y) ———— x - y
x.mul(y)、x.rmul(y) ———— x * y
x.trueiv(y)、x.rtrueiv(y) ———— x / y
x.floordiv(v)、x.rfloordiv(v) ———— x // y
x.mod(y)、x.rmod(y) ———— x % y
x.divmod(y)、x.rdivmod(y) ———— divmod(x, y)
x.pow(y)、x.rpow(y) ———— x ** y
x.lshift(y)、x.rlshift(y) ———— x << y
x.rshift(y)、x.rrshift(y) ———— x >> y
x.and(y)、x.rand(y) ———— 按位与运算:x & y
x.or(y)、x.ror(y) ———— 按位或运算:x | y
x.xor(y)、x.rxor(y) ———— 按位异或运算:x ^ y
前缀“r”有与无的区别,以加法 x+y 为例:
1、x 有 add 方法,且不返回 NotImplemented,则调用x.add(y)。
2、x 没有 add 方法,或者调用 add 方法返回 NotImplemented,则检查 y 有没有 radd 方法,如果有,且不返回 NotImplemented,则调用 y.radd(x)。
3、x 没有 add 方法,或者调用 add 方法返回 NotImplemented,且 y 也没有 radd 方法, 或者调用 radd 方法返回 NotImplemented,则抛出 TypeError异常。
x.iadd(y) ———— x += y
x.isub(y) ———— x -= y
x.imul(y) ———— x *= y
x.itrueiv(y) ———— x /= y
x.ifloordiv(v) ———— x //= y
x.imod(y) ———— x %= y
x.idivmod(y) ———— 整除与取余:x= divmod(x, y)
x.ipow(y) ———— x **= y
x.ilshift(y) ———— x <<= y
x.irshift(y) ———— x >>= y
x.iand(y) ———— x &= y
x.ixor(y) ———— x ^= y
x.ior(y) ———— x |= y
x.neg() ———— -x
x.pos() ———— +x
x.abs() ———— abs(x)
x.invert() ———— ~x
x.complex() ———— complex(x)
x.int() ———— int(x)
x.float() ———— float(x)
x.round() ———— round(x)
x.round(n) ———— round(x, n)
x.ceil() ———— math.ceil(x)
x.floor() ———— math.floor(x)
x.trunc() ———— math.trunc(x)
a_list[x.index()] ———— a_list[x]
x.bool() ———— bool(x)
三、比较魔法方法
x.eq(y) ———— x == y
x.ne(y) ———— x != y
x.lt(y) ———— x < y
x.le(y) ———— x <= y
x.gt(y) ———— x > y
x.ge(y) ———— x >= y
四、序列化魔法方法
x.copy() ———— copy.copy(x)
x.deepcopy() ———— copy.deepcopy(x)
x.getstate() ———— pickle.dump(x, file)
x.reduce() ———— pickle.dump(x, file)
x.reduce_ex(protocol_version) ———— pickle.dump(x, file, protocol_version)
x.getnewargs() ———— x = pickle.load(fp)
x.setstate() ———— x = pickle.load(fp)
五、与with 语句相关的魔法方法
x.enter() ———— 进入with语句块 with x:
x.exit(exc_type, exc_value, traceback) ———— 退出with语句块 with x:
六、与类、属性相关的魔法方法
x.new() ———— 创建对象前:MyObj = MyClass()
x.del() ———— del x
x.solts() ———— 设置允许绑定的属性
x.hash() ———— hash(x)
type(x).dict[‘color’].get(x, type(x)) ———— 获得一个属性的值:x.color
type(x).dict[‘color’].set(x, ‘PapayaWhip’) ———— 设置一个属性的值:x.color = ‘PapayaWhip’
type(x).dict[‘color’].del(x) ———— 删除一个属性:del x.color
MyClass.instancecheck(x) ———— isinstance(x, MyClass)
MyClass.subclasscheck© ———— isinstance(C, MyClass)
MyABC.subclasshook© ———— isinstance(C, MyABC)
七、new() 函数
new()函数原本是系统自己定义、自动调用的一个函数。系统在执行“myObj=myCls()”这一句时,首先是调用 myCls 类的__new__()来创建一个对象,并返回这个新创建的对象,系统然后再将这个对象作为实数赋给__init__()的第一个形参进行对象的初始化,最后系统将初始化之后的对象赋给myObj,完成对象的创建。
也就是说,在创建对象时,系统先自动调用__new__()函数,然后自动调用__init__()函数。系统把当前类作为一个实参赋给__new__()函数的第一个形参,把__new__()创建的对象作为一个实参赋给__init__()函数的第一个形参。
如果在类中没有重载__new__()函数,则显然是调用父类的同名函数,父类也没有重载,则继续往上溯源,直到object类这个类的鼻祖。object类中__new__()是如何创建对象,也就是创建对象的语句是不公开的。在定义类时,可以重载__new__()函数,但是,因为不可能自己编写实际创建对象的语句,所以在重载__new__()函数时,在最后都必须要调用object.new()来创建对象并返回。也就是说,所有的重载,实际上都是在object.new_()基础之上的扩展。例如:
class c01:
def __new__(cls, *args, **kwargs):
print('This is new')
return super().__new__(cls, *args, **kwargs)
def __init__(self):print('This is init')
obj01=c01() # This is new This is init
print(obj01) # <__main__.c01 object at 0x00000000024E7910>
obecet类的__new__()函数的功能是创建一个类对象,但创建哪个类的对象,是由第一个参数决定的。如果创建出来的不是当前类的对象,则当前类的构造函数不会被调用。例如:
class c02:
def __init__(self):print('This is c02 init')
class c03:
def __new__(cls, *args, **kwargs):
print('This is new')
return super().__new__(c02, *args, **kwargs)
def __init__(self):print('This is c03 init')
obj02=c03() # 因为实际创建出的不是c03类对象,c03类构造函数不被调用:This is new
print(obj02) # 实际创建出的不是c02类对象:<__main__.c02 object at 0x0000000001D97C40>
obj03=c02() # This is c02 init
需要重载__new__()函数的地方不是很多,但在特殊情况下,有时只能用它。例如,我们需要一个永远都是正数的整数类型:
class myInt(int):
def __new__(cls, v):return super().__new__(cls, abs(v))
x = myInt(-88)
print (x) # x 是整数类型,但永远不会为负:88
来源:CSDN
作者:Jeff888999
链接:https://blog.csdn.net/Jeff888999/article/details/104114068