python魔法方法长文详解

python魔法方法详解

1. 什么是魔法方法

魔法方式(Magic methods)是python的内置函数,一般以双下划线开头和结尾,比如__add__,__new__等。每个魔法方法都有对应的一个内置函数或者运算符。当我们个对象使用这些方法时,相当于对这个对象的这类方法进行重写(如运算符重载)。魔法方法的存在是对类或函数进行了提炼,供python解释器直接调用。当使用len(obj)时,实际上调用的就是obj.__len__方法,其它同理。

如我们对某个类A定义了__add__方法,那么可以直接通过a1+a2(a1,a2分别为A的实例)来实现自定义的“相加”,python会识别+并调用该对象对应的__add__方法来运行,而无需像一般的方法一样通过a1.add(a2)来实现。这就是为什么说魔法方法本质是对一些函数进行了提炼和封装,可以方便的赋予对象更多的方法。

dir()可以查看对象的所有方法和属性,其中双下划线开头和结尾的就是该对象具有的魔法方法。以整数对象为例:

>>>dir(int)
['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'as_integer_ratio', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']

可以看到,整数对象下具有__add__方法,这也是为什么我们可以直接在python中运算1+2,当python识别到+时,就去调用该对象的__add__方法来完成计算。比如我们想给自己的对象定义+方法:

class A:
    def __init__(self,a):
        self.a=a
    def __add__(self,others):
        print('this is a magic method')
        return [self.a,others.a]
    
>>>a=A(1)
>>>b=A(3)
>>>c=a+b#自定义的__add__方法,实现是将两个对象的a属性合并到一个列表中
this is a magic method#+调用的是__add__方法
>>>c
[1, 3]

>>>a.__add__(b)#等价于直接调用
this is a magic method
[1, 3]

同理,再举一个__len__魔法方法的例子来帮助理解。我们定义一个list对象l,通过dir(l)可以看到该对象中具有__len__方法,即表明在python中可以通过len(l)来返回其列表长度。我们在自己定义的对象中当然也可以自定第该方法,来实现我们想通过len()返回的结果。

>>>l=[1,2,3]
>>>dir(l)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
>>>len(l)
3

自定义一个对象:

class B:
    def __init__(self,a):
        self.a=a
        
>>>b=B(1)
>>>len(b)#因为对象中未定义__len__,因此调用len(b)会报错,没有该方法
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: object of type 'B' has no len()
    
#添加__len__方法
class B:
    def __init__(self,a):
        self.a=a
    def __len__(self):
        print('this is magic method len')
        return 2
>>>a=B(1)
>>>print(len(a))
this is magic method len
2

可以看到,魔术方法在类或对象的某些事件出发后会自动执行,如果希望根据自己的程序定制特殊功能的类,那么就需要对这些方法进行重写。使用这些「魔法方法」,我们可以非常方便地给类添加特殊的功能。

2. 几类常用的魔法方法

魔法方法大致分为如下几类:

  • 构造与初始化
  • 类的表示
  • 访问控制
  • 比较、运算等操作
  • 容器类操作
  • 可调用对象
  • 序列化

2.1 构造与初始化

对类的初始化一般会涉及三个魔法方法,__init__,__new____del__;

当我们初始化一个类是,a=A(1),首先调用的并不是__init__函数,而是__new__;初始化一个类有两步,分别为:

a. 调用该类的__new__方法,并返回该类的实例对象;

b. 调用该类的__init__方法,对实例对象进行初始化。

其中__new__用法如下:

(1) __new__(cls,*args,**kwargs):至少要有一个参数cls,代表传入的类,此参数在实例化时由 Python 解释器自动提供,若返回该类的对象实例,后面的参数直接传递给__init__

(2) __new__可以决定是否使用__init__方法,但是,执行了__new__,并不一定会进入__init__,只有__new__返回了,当前类cls的实例,当前类的__init__才会进入。即使返回父类的实例也不行,必须是当前类的实例;

(3) object将__new__()方法定义为静态方法,并且至少需要传递一个参数cls,cls表示需要实例化的类,此参数在实例化时由Python解释器自动提供。

(4) __init__()有一个参数self,该self参数就是__new__()返回的实例

举例理解:

class A:
    def __init__(self,a,b):
        print('this is A init')
        print(self)
        self.a=a
        self.b=b
    def __new__(cls, *args, **kwargs):
        print('this is A new')
        print('args:%s'%args)
        print('kwargs:%s'%kwargs)
        print(cls)
        print(object.__new__(cls<
  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值