Python 入门 17 —— 类的魔法方法、__new__()、 __ call__()

类的魔法方法实质是 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.__ call__() ———— 对象被调用
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>

object.__ 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

八、__ call__() 函数

当类的对象被像函数一样调用时,__ call__() 函数被系统自动调用。也就是说,“对象名(参数)”等同于“对象名.__ call__()(参数)”。例如:

class c04:
    def __init__(self,x): self.a = x*100
    def __call__(self,x,y): return (x+y)*self.a

obj04=c04(3)
print(obj04(8,9))    # 5100
print(obj04.__call__(8,9))    # 5100

那么,有__call__() 类能否被直接调用呢?不能。因为“类名(参数)”已经被赋予了一个十分明确的意义,那就是创建一个类对象。

———————————————— 本篇完 ————————————————

看完之后,麻烦您顺手点击下方 “点赞” 两个字给我点个赞吧 ^-^ , 谢谢您了。

如果您还能像我小学一年级班主任好老师那样,给我随心写上几句表扬或批评的话语,那真是感激不尽!

在我人生的道路上,有了您的鼓励和指导,我一定成长快快。

发布了28 篇原创文章 · 获赞 6 · 访问量 2271

猜你喜欢

转载自blog.csdn.net/Jeff888999/article/details/104114068
今日推荐