查看原文
其他

会变 "魔术" 的 Python

2018-02-04 刘志军 Python爱好者社区

作者:刘志军,6年+Python使用经验, 高级开发工程师,目前在互联网医疗行业从事Web系统构架工作

个人公众号:Python之禅(微信ID:vttalk)


Python 最吸引你的地方是什么?

整洁的代码缩进格式?丰富的第三方包?更高的开发效率?还是良好的跨平台性?

这些特性都不足以说明 Python 的优点,最吸引人的应该是动态性所带来的灵活与便利性。

你可能听过说一个词叫做「鸭子类型」,所谓鸭子类型就是只要它走路像鸭子,叫起来像鸭子,那么你就可以认为它是鸭子

而 Python 就有这种魔力使得任何东西都可以是鸭子,这种魔力就源自于语言的动态性, Python 提供了很多魔术方法,使得鸡可以像鸭子一样游泳

所谓魔术方法就是由 Python 内部定义,具有特殊作用的方法,这些方法有一个共同特征,以双下划线开始并以双下划线结尾,比如对象的初始化方法 __init__,是最常用的一个魔术方法(不少初学者以为只有一个下划线,在这栽了跟头)

如何使用这些魔术方法呢?

先来看一个例子

我们都知道数字可以相加,字符串也可以相加

>>> 1+2
3
>>> "hello"+" Python"
'hello Python'

列表也可以相加

>>> [1,2,3] + [4,5,6]
[1, 2, 3, 4, 5, 6]

那么两个对象(这里特指类的实例对象)可不可以相加呢?

class Point:
   def __init__(self, x, y):
       self.x = x
       self.y = y

   def __repr__(self):
       return "Point({}, {})".format(self.x, self.y)

>>> (Point(1, 2) + Point(3, 4))
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'Point' and 'Point'
>>>

上面用 Point 类表示坐标系中的一个点,x,y 分别代表横轴和纵轴,两个点相加时报错了,错误日志告诉我们,对于 Point 类不支持 「+」操作。

但如果你实现了魔术方法 __add__ 就可以支持加操作了

class Point:
   ...

   def __add__(self, other):
       assert isinstance(other, Point)
       return Point(self.x + other.x, self.y + other.y)

再来运行:

>>> Point(1, 2) + Point(3, 4)
Point(4, 6)

再举一个例子

我们知道类的属性一般都是用点操作获取属性,例如p.x,p.y,而访问字典对应的key值都是通过 p[‘x’] 或者 p.get(“x”) 来访问的,那字典可不可以用 “.” 的方式获取呢?

>>> d = {"a":"b"}
>>> d.a
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'a'

显然,默认情况下是不允许通过“.”的方式获取的,但是如果你实现了魔术方法__getattr__就可以使用点的方式获取了。

我们自定义一个类,继承 dict,再实现 __getattr__方法就可以用“.”操作了,当属性使用 a.b 的方式访问时,就会调用 __getattr__

>>> class MyDict(dict):
...     def __getattr__(self, item):
...         return self.get(item)
...
>>> d = MyDict(a="b")
>>> d
{'a': 'b'}
>>> d['a']
'b'
>>> d.a
'b'

如果你熟悉 Django 中 Template 语法的话,你现在应该知道为什么字典对象可以使用“.”操作获取里面的元素。

当然,魔术方法远不止这两个,全部加起来有近百来个


  • 关于实例构建与初始化的,比如 __new__,__init__

  • 关于属性访问控制:__getattr__,__setattr__

  • 描述符相关的:__get__, __set__

  • 关于操作容器的: __getitem__,__setitem__

  • 关于上下文管理的:__enter__,__exit__

  • 比较运算符:__cmp__,__eq__,__lt__,__gt__

  • 算术运算符:__add__,__sub__,__mul__,__div__

Python爱好者社区历史文章大合集

Python爱好者社区历史文章列表(每周append更新一次)

福利:文末扫码立刻关注公众号,“Python爱好者社区”,开始学习Python课程:

关注后在公众号内回复“课程”即可获取:

小编的Python入门视频课程!!!

崔老师爬虫实战案例免费学习视频。

丘老师数据科学入门指导免费学习视频。

陈老师数据分析报告制作免费学习视频。

玩转大数据分析!Spark2.X+Python 精华实战课程免费学习视频。

丘老师Python网络爬虫实战免费学习视频。


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存