流畅的python——4月18日读书笔记"/>
流畅的python——4月18日读书笔记
1 python特殊方法
collections 是一个Python内建的一个集合模块,提供了许多有用的集合类
namedtuple 方法是一个很好的定义数据的方式。比如我们这次需要定义一个元组,包含的信息为花色与大小,就可以定义一个Card的数据类型,长度为2。用这种方式定义的好处就是可以直接通过属性的方式调用,很方便。
import collections
Card = collections.namedtuple('Card', ['rank', 'suit'])class FrenchDeck:# 在python3中,对object的继承关系是默认的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]
然后我在控制台做一些操作:
首先是创建一个FrenchDeck类的实例,然后用len()方法看一下它的长度。
>>> from cards_1_1 import FrenchDeck
>>> deck = FrenchDeck()
>>> len(deck)
52
然后取第一个和最后一个元素。实际上是通过__getitem__的方式。
>>> deck[0]
Card(rank='2', suit='spades')
>>> deck[-1]
Card(rank='A', suit='hearts')
然后再用python内置的random模块,其中的random.choice()方法来随机取一个元素。
>>> from random import choice
>>> card = choice(deck)
>>> card
Card(rank='8', suit='hearts')
其中__getitem__和__len__都属于特殊方法,我们在调用len()的时候,实际上也是通过调用self.__len__方法
特殊方法的存在是给Python解释器调用的,我们并不需要调用。同时,如果是自定义类,我们可以对这些特殊方法进行重写。
类似的比较常用的特殊方法调用总结下:
调用方法 | Python 实际调用方法 | 说明 |
---|---|---|
x = MyClass() | x.__ init__() | 初始化一个实例 |
str(x) | x.__ str__() | 字符串的值 |
bytes(x) | x.__ byte__() | 字节数组的值 |
iter(seq) | seq.__ iter__() | 遍历某个序列 |
reversed(seq) | seq.__ reversed__() | 按逆序创建一个迭代器 |
len(seq) | seq.__ len__() | 序列的长度 |
x in seq | seq.__ contains__(x) | 某序列是否包含特定的值 |
x[key] = value | x.__ setitem__(key, value) | 通过键来设置值 |
x + y | x.__ add__(y) | 加法 |
x - y | x.__ sub__(y) | 减法 |
x * y | x.__ mul__(y) | 乘法 |
x / y | x.__ truediv__(y) | 除法 |
x % y | x.__ mod__(y) | 取模(取余) |
x ** y | x.__ pow__(y) | 幂数 |
bool(x) | x.__ bool__() | 判断x的值为True/False |
另外,__getitem__方法将[]的操作交给了self.cards列表,那么我们可以对deck进行切片操作,切片操作有3个参数(start_index,stop_index,step)。第一个参数默认为第一个元素,第二个默认为最后一个元素,step默认为1。通过切片操作,我们可以很快的提取我们想要的元素。
实例如下:
>>> deck[1:6:2]
[Card(rank='3', suit='spades'), Card(rank='5', suit='spades'), Card(rank='7', suit='spades')]
__getitem__方法同时也将对象变成可迭代的。可以使用"in",它会按顺序做一次迭代的搜索。
在众多特殊方法中__repr__方法能把一个对象用字符串的形式表达出来。否则我们在控制台打印出来的对象可能是<Data object at 0x10e100070>这个样子的,返回了他的内存地址。它跟__str__的区别就在于,后者是当使用str()函数或者print()函数打印一个对象时被调用的,但是当一个对象没有__str__函数的时候,解释器就会用__repr__作为替代。
前者方便我们调试与记录日志信息,后者则是给终端用户看的。
例子如下:
class Test:def __init__(self, value="testing"):self.data = valueclass TestStr(Test):def __str__(self):return '[Value: %s]' % self.dataclass TestRepr(Test):def __repr__(self):return 'TestRepr(%s)' % self.data
>>> from cards_1_1 import Test, TestStr, TestRepr
>>> tr = TestRepr()
>>> ts = TestStr()
>>> tr
TestRepr(testing)
>>> ts
<cards_1_1.TestStr instance at 0x10964d758>
>>> print(tr)
TestRepr(testing)
>>> print(ts)
[Value: testing]
重构__repr__方法后,无论是输出对象tr时,还是print时直接按照定义的方式打印出来了。
而直接输出对象ts时并没有按我们__str__方法中定义的格式进行输出,而用print输出的信息却改变了。
通过特殊方法,我们可以将自定义的数据类型表现得与内置的数据类型一样
更多推荐
流畅的python——4月18日读书笔记
发布评论