Python数据模型

1.1 __getitme__和__len__方法

import collections

from randomimport choice    # 序列中随机选出一个元素

card = collections.namedtuple('card', ['rank', 'suit'])

class FrenchDeck:

    ranks = [str(i)for iin range(2,11)] +list('JQKA')

    suits ='spades diamonds clubs hearts'.split()

    def __init__(self):

    self._cards = [card(rank, suit)for suitin self.suits

    for rankin self.ranks]

    def __len__(self):

    return len(self._cards)

    def __getitem__(self, item):

    return self._cards[item]

因为__getitem__方法把[]操作交给了self._cards列表,所以我们的deck类自动支持切片操作

print(deck[:3)     #   [card(rank='2', suit='spades'), card(rank='3', suit='spades'), card(rank='4', suit='spades')]

只获取A的牌,取出所以12的那张牌,然后每隔13张获取一张牌

print(deck[12::13])  # [card(rank='A', suit='spades'), card(rank='A', suit='diamonds'), card(rank='A', suit='clubs'), card(rank='A', suit='hearts')]

另外,仅仅实现了__getitem__方法,就变成可迭代的了

for cardin deck:

    print(card)

可迭代

for cardin deck:

print(card)

反向迭代




代码示例

字符串表示形式:

    python中有一个内置的函数repr,它能把一个对象用字符串形式表达出来以便辨认,这就算‘字符串表示形式’, repr就是通过__repr__这个特殊方法得到一个对象的字符串表示形式,如果没有实现__repr__,当我们在控制台打印实例是,得到字符串可能会是<__main__.Vector object at 0x00672690>  

def __repr__(self):

    return 'Vector(%r,%r)' %(self.x, self.y)

%r来获对象各个属性的标准字符串表示形式  # Vector(1,'3')   Vector(1,3)   会显示是字符串还是数值

__repr__和__str__的区别在于,后者实在str()函数被使用,或实在print函数打印一个对象时才被调用,并且它返回的字符串对终端用户更友好。

如果你想实现这两个特殊方法的一个,__repr__是更好的选择,因为如果一个对象没有__str__函数,而python又需要调用它的时候,解释器会用__repr__作为代替。

算术运算符:

通过__add__和__mul__,提供了 + 和 * 这两个算术运算符。值得注意的是,这两个方法的返回值都是新创建的对象,被操作的两个值(self或other)还是原封不动,代码里只是读取了它们的值而已,算术运算符的基本原则就是不改变操作对象,而是产出一个新的值。

自定义的布尔值:

尽管python理由bool类型,但实际上人核对下都可以用于需要布尔值的上下文中(比如if 或while语句,或者and、or、not运算符)。为了判定一个值X为真还是为假,python会调用bool(x),这个函数只能返回True或False。

默认情况下,我们自定义的类的实例总被认为是真的,除非这个类对__bool__或者__len__函数有自己的实现。bool(x)的背后是调用x.__bool__()的结果;如果不存在__bool__方法,那么bool(x)会尝试调用x.__len__(),如果返回0,则bool会返回False;否则返回True。

我们对__bool__的实现很简单,如果一个向量的模是0,那么就返回False,其他情况返回True。因为__bool__函数的返回类型应该是布尔值,所以我们通过bool(abs(self))把模变成了布尔值。

如果想让Vector.__bool__更加高效,可以采用

def __bool__(self):

    return bool(self.x or self.y)

它不那么易读,但却能省掉从abs到__abs__到平方在平方根这些中间步骤,通过bool把返回类型显式转换为布尔值是为了符合__bool__对返回值的规定,因为or运算符可能会返回x或y本身的值,若x的值等价于真,则or返回x的值;否则返回y的值

特殊方法一览:

跟运算符无关的特殊方法

类别                                                                       方法名

字符串/字节序列表现形式:                      __repr__、__str__、__format__、__bytes__

数制转换:  __abs__、__bool__、__complex__、__int__、__float__、__hash__、__index__     

集合模拟: __len__、__getitem__、__setitem__、__delitem__、__contains__

迭代枚举: __item__、__reversed__、__next__

可调用模拟:__call__

上下文管理:__enter__、__exit__

实例创建和销毁:__new__、__init__、__del__

属性管理:__getattr__、__getattribute__、__setattr__、__delattr__、__dir__

属性描述符:__get__、__set__、__delete__

跟类相关的服务:__prepare__、__instancecheck__、__subclasscheck__

跟运算符相关的特殊方法

一元运算符:__neg__ -、__pos__ + 、__abs__、abs()

众多比较运算符:__lt__  < 、__le__ <= 、__eq__ == 、__ne__ != 、__gt__ > 、 __ge__ >= 、

算数运算符:__add__ + 、 __sub__ - 、 __mul__ * 、__truediv__ / 、__floordiv__ // 、__mod__ %、__divmod__ divmod()、__pow__ ** 或pow()、__round__ round()

反向算术运算符:__radd__、__rsub__、__rmul__、__rtruediv__、__rfloordiv__、__rmod__、__rdivmod__、

增量赋值算术运算符:__iadd__、__isub__、__imul__、__itruediv__、__ifloordiv__、__imod__、__ipow__

位运算符:__invert__ ~、__lshift__ << 、__rshift__ >> 、__and__ &、__or__ | 、__xor__ ^ 、

反向位运算符: __rlshift__、__rrshift__、__rand__、__rxor__、__ror__

增量赋值位运算符: __ilshift__、__irshift__、__iand__、__ixor__、__ior__

当交换两个操作数的位置时,就会调用反向运算符(b * a 而不是 a * b),增量赋值运算符则是一种把中缀运算符变成赋值运算的捷径(a = a * b 就变成 a * = b)


为什么len不是普通方法

如果x是内置类,那么len(x)的速度很快,原因是CPython会直接从一个C结构体里读取对象长度,完全不会调用任何方法。abs也是同理

小结

通过实现特殊方法,自定义数据类型可以表现的跟内置类型一样,从而写出更具Python风格的代码

Python对象的一个基本要求就是它得有合理的字符串表示形式,我们可以通过__repr__和__str__来满足这个要求。前者方便我们调试和记录日志,后者则是给终端用户看。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容