流畅的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 seqseq.__ contains__(x)某序列是否包含特定的值
x[key] = valuex.__ setitem__(key, value)通过键来设置值
x + yx.__ add__(y)加法
x - yx.__ sub__(y)减法
x * yx.__ mul__(y)乘法
x / yx.__ truediv__(y)除法
x % yx.__ mod__(y)取模(取余)
x ** yx.__ 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 = value


class TestStr(Test):
    def __str__(self):
        return '[Value: %s]' % self.data


class 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输出的信息却改变了。

通过特殊方法,我们可以将自定义的数据类型表现得与内置的数据类型一样

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值