本文转载自微信公众号「PythonMind」,作者dongfanger。转载本文请联系PythonMind公众号。
热爱Python
Python是Guido van Rossum设计出来的让使用者觉得如沐春风的一门编程语言。2020年11月12日,64岁的Python之父宣布由于退休生活太无聊,自己决定加入Microsoft的DevDiv Team,致力于“确保更好地使用Python”。尽管在国内有些声音在Diss着Python,认为它太简单,只是个脚本语言,但是它的发明者对Python的热情,仍然激励着我们坚持对Python的热爱。
龟叔是所有编程语言发明者当中头发最多的这位。
奇迹时刻
collection.len()是面向对象语言的写法,len(collection)是Python语言的写法,这种风格叫做Pythonic。从前者到后者,就像变魔术一样,一瞬间让人眼前一亮。这个魔术就是Python魔法方法,或者叫双下方法,它是用双下划线开头和双下划线结尾的特殊方法,比如obj[key],Python解释器实际上会转换成obj.__getitem__(key)来运行,但是使用者并无感知。
__getitem__和__len
____getitem__用来获取数据,__len__用来返回长度,这2个魔法方法是Python基础,我们通过一副扑克牌来了解:
- import collections
- # 定义一副牌
- Card = collections.namedtuple('Card', ['rank', 'suit'])
- class FrenchDeck:
- # 大小
- ranks = [str(n) for n in range(2, 11)] + list('JQKA')
- # 花色
- suits = 'spades diamonds clubs hearts'.split()
- def __init__(self):
- # 生成一副牌
- self._cards = [Card(rank, suit) for suit in self.suits
- for rank in self.ranks]
- def __len__(self):
- return len(self._cards)
- def __getitem__(self, position):
- return self._cards[position]
本来我们对这副牌什么都不能做,但是由于实现了__len__,可以使用len()函数查看有多少张牌:
- >>> len(deck)
- 52
由于实现了__getitem__,可以使用中括号索引取值:
- >>> deck[0]
- Card(rank='2', suit='spades')
能进行切片:
- >>> deck[:3]
- [Card(rank='2', suit='spades'), Card(rank='3', suit='spades'), Card(rank='4', suit='spades')]
- >>> deck[12::13]
- [Card(rank='A', suit='spades'), Card(rank='A', suit='diamonds'), Card(rank='A', suit='clubs'), Card(rank='A', suit='hearts')]
能迭代:
- >>> for card in deck: # doctest: +ELLIPSIS
- ... print(card)
- Card(rank='2', suit='spades')
- Card(rank='3', suit='spades')
- Card(rank='4', suit='spades')
- ...
发现没有,魔法方法是可以用来装B的!别人写个类只能get、set,你写个类还能花式炫技,666。
Python魔法方法是给Python解释器使用的,一般不需要直接调用,Python会自己去调,比如把len(my_object)写成my_object.__len__(),就弄巧成拙了。
魔法方法实现运算符
前面例子实现了取值和长度,接着再看一个例子,使用__repr__、__abs__、__bool__、__add__、__mul__,实现运算符:
- from math import hypot
- # 二维向量
- class Vector:
- def __init__(self, x=0, y=0):
- self.x = x
- self.y = y
- # 表达式
- def __repr__(self):
- return 'Vector(%r, %r)' % (self.x, self.y)
- # 绝对值
- def __abs__(self):
- return hypot(self.x, self.y)
- # 布尔值
- def __bool__(self):
- return bool(abs(self))
- # 加法
- def __add__(self, other):
- x = self.x + other.x
- y = self.y + other.y
- return Vector(x, y)
- #乘法
- def __mul__(self, scalar):
- return Vector(self.x * scalar, self.y * scalar)
__add__实现了加法:
- >>> v1 = Vector(2, 4)
- >>> v2 = Vector(2, 1)
- >>> v1 + v2
- Vector(4, 5)
__abs__实现了绝对值:
- >>> v = Vector(3, 4)
- >>> abs(v)
- 5.0
__mul__实现了乘法:
- >>> v * 3
- Vector(9, 12)
__repr__实现了对象的字符串表示:
- Vector(4, 5)
否则得到的字符串可能是
__bool__实现了布尔值:
- if Vector(4, 5):
- return True
其他魔法方法
一篇文章是讲不完魔法方法的,我们会在后续文章中,继续探讨如何使用和实现它们。
Tips
本小节内容是我看《流畅的Python》第一遍时记录的知识点:
- beer_card = Card('7', 'diamonds')
2021年3月24日,主题为《数据的世界,世界的数据》的星环科技2021春季新品发布会...
建站 什么 虚拟主机 够用?这要看搭建的是什么类型的网站。比如个人博客类型的网...
在Python语言中有如下3种方法: 成员方法 类方法(classmethod) 静态方法(staticm...
前提条件 请您在购买前确保已完成注册和充值。详细操作请参见 如何注册公有云管...
【51CTO.com快译】 数据可视化工具不断发展,提供更强大的功能,同时改善可访问...
本文整理自直播《Hologres 数据导入/导出实践-王华峰(继儒)》 视频链接: https:/...
信息化2.0时代提出开展智慧教育创新发展行动。2019年2月,中共中央、国务院印发...
Docker生成新镜像版本的两种方式 There are two ways Docker can generate new m...
摘要 元旦期间 订单业务线 告知 推送系统 无法正常收发消息,作为推送系统维护者...
从 10.0.0 版开始,异步迭代器就出现在 Node 中了,在本文中,我们将讨论异步迭...