Python中常见魔法方法介绍

5a6fbee003d0a997fe180c20f9f53dd8.gif

新钛云服已累计为您分享660篇技术干货

64199fa64b1fbdbe45ec9400f396add1.gif


什么是魔法方法?

魔法方法(Magic Methods)是Python中的内置函数,一般以双下划线开头和结尾,例如__init____del__等。之所以称之为魔法方法,是因为这些方法会在进行特定的操作时会自动被调用。

在Python中,可以通过dir()方法来查看某个对象的所有方法和属性,其中双下划线开头和结尾的就是该对象的魔法方法。以字符串对象为例:

 
 
>>> dir("hello")
['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
'__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__mo
d__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__', '_formatter_field_name_split', '_formatter_parser', 'capitalize', 'center',
'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'index', 'isalnum', 'isalpha', 'isdigit', 'isl
ower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition', 'replace', 'rfind', 'rindex', '
rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate'
, 'upper', 'zfill']

可以看到字符串对象有__add__方法,所以在Python中可以直接对字符串对象使用"+"操作,当Python识别到"+"操作时,就会调用该对象的__add__方法。有需要时我们可以在自己的类中重写__add__方法来完成自己想要的效果。

 
 
class A(object):
  def __init__(self, str):
      self.str = str

•   def __add__(self, other):
•       print ('overwrite add method')
•       return self.str + "---" + other.str

>>>a1 = A("hello")
>>>a2 = A("world")
>>>print (a1 + a2)
>>>overwrite add method
>>>"hello---world"

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

常用的魔法方法

1、构造与初始化

__new____init__ 这两个魔法方法常用于对类的初始化操作。上面我们创建a1 = A("hello")时,但首先调用的是__new__;初始化一个类分为两步:    

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

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

__new__(cls, *args, **kwargs)至少需要一个cls参数,代表传入的类。后面两个参数传递给__init__。在__new__可以决定是否继续调用__init__方法,只有当__new__返回了当前类cls的实例,才会接着调用__init__。结合__new__方法的特性,我们可以通过重写__new__方法实现Python的单例模式:

class Singleton(object):
  def __init__(self):
      print("__init__")

•   def __new__(cls, *args, **kwargs):
•       print("__new__")
•       if not hasattr(Singleton, "_instance"):
•           print("创建新实例")
•           Singleton._instance = object.__new__(cls)
•       return Singleton._instance

>>> obj1 = Singleton()
>>> __new__
>>> 创建新实例
>>> __init__
>>> obj2 = Singleton()
>>> __new__
>>> __init__
>>> print(obj1, obj2)
>>> (<__main__.Singleton object at 0x0000000003599748>, <__main__.Singleton object at 0x0000000003599748>)

可以看到虽然创建了两个对象,但两个对象的地址相同。

2、控制属性访问这类魔法

方法主要对对象的属性进行访问、定义、修改时起作用。主要有:

__getattr__(self, name): 定义当用户试图获取一个属性时的行为。

__getattribute__(self, name):定义当该类的属性被访问时的行为(先调用该方法,查看是否存在该属性,若不存在,接着去调用getattr)。

__setattr__(self, name, value):定义当一个属性被设置时的行为。

当初始化属性时如self.a=a时或修改实例属性如ins.a=1时本质时调用魔法方法self.__setattr__(name,values);当实例访问某个属性如ins.a本质是调用魔法方法a.__getattr__(name)

3、容器类操作    

有一些方法可以让我们自己定义自己的容器,就像Python内置的List,Tuple,Dict等等;容器分为可变容器和不可变容器。

如果自定义一个不可变容器的话,只能定义__len__和__getitem__;定义一个可变容器除了不可变容器的所有魔法方法,还需要定义__setitem__和__delitem__;如果容器可迭代。还需要定义__iter__。

__len__(self):返回容器的长度  

__getitem__(self,key):当需要执行self[key]的方式去调用容器中的对象,调用的是该方法    

__setitem__(self,key,value):当需要执行self[key] = value时,调用的是该方法

__iter__(self):当容器可以执行 for x in container:,或者使用iter(container)时,需要定义该方法

下面举一个例子,实现一个容器,该容器有List的一般功能,同时增加一些其它功能如访问第一个元素,最后一个元素,记录每个元素被访问的次数等。

class SpecialList(object):
    def __init__(self, values=None):
        self._index = 0
        if values is None:
            self.values = []
        else:
            self.values = values
        self.count = {}.fromkeys(range(len(self.values)), 0)

    def __len__(self):  # 通过len(obj)访问容器长度
        return len(self.values)

    def __getitem__(self, key):  # 通过obj[key]访问容器内的对象
        self.count[key] += 1
        return self.values[key]

    def __setitem__(self, key, value):  # 通过obj[key]=value去修改容器内的对象
        self.values[key] = value

    def __iter__(self):  # 通过for 循环来遍历容器
        return iter(self.values)

    def __next__(self):
        # 迭代的具体细节
        # 如果__iter__返回时self 则必须实现此方法
        if self._index >= len(self.values):
            raise StopIteration()
        value = self.values[self._index]
        self._index += 1
        return value

    def append(self, value):
        self.values.append(value)

    def head(self):
        # 获取第一个元素
        return self.values[0]
    
    def last(self):
        # 获取最后一个元素
        return self.values[-1]

 这类方法的使用场景主要在你需要定义一个满足需求的容器类数据结构时会用到,比如可以尝试自定义实现树结构、链表等数据结构(在collections中均已有),或者项目中需要定制的一些容器类型。

总结

魔法方法在Python代码中能够简化代码,提高代码可读性,在常见的Python第三方库中可以看到很多对于魔法方法的运用。

因此当前这篇文章仅是抛砖引玉,真正的使用需要在开源的优秀源码中以及自身的工程实践中不断加深理解并合适应用。

了解新钛云服

· 新钛云服成为国内首家荣获 Gartner Customer First 徽章的云和安全管理服务商!

· 新钛云服荣膺“2022爱分析 · IT运维厂商全景报告”云管理平台CMP 代表厂商!

· 新钛云服荣膺第四届FMCG零售消费品行业CIO年会「年度数字化服务最值得信赖品牌奖」

· 新钛云服A轮融资数千万元!获资本和客户双重青睐!

· 新钛云服三周岁,公司月营收超600万元,定下百年新钛的发展目标

· 当IPFS遇见云服务|新钛云服与冰河分布式实验室达成战略协议

· 深耕专业,矗立鳌头,新钛云服获千万Pre-A轮融资

· 新钛云服一周年,完成两轮融资,服务五十多家客户

往期技术干货

· 万字长文:云架构设计原则|附PDF下载

· 万字长文 | 使用 RBAC 限制对 Kubernetes 资源的访问

· 万字长文 | 面向k8s编程,如何写一个Operator

· Terraform 实战 | 万字长文

· 万字长文 | 在 Kubernetes 中部署高可用应用程序的最佳实践!

· CephFS性能基准测试与集群优化 | 万字总结

· 低代码开发,全民开发,淘汰职业程序员!

· 国内主流公有云VPC使用对比及总结

· Ceph OSD故障排除|万字经验总结

· 运维人的终身成长,从清单管理开始|万字长文!

· OpenStack与ZStack深度对比:架构、部署、计算存储与网络、运维监控等

· IT混合云战略:是什么、为什么,如何构建?

b64ad4fe875b7ccc947a5430ac77496a.gif

点👇分享

27a65101624c829442bb0c537b1d285a.gif

戳👇在看

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值