Python的特殊方法

作者: SHISHENGJIA | 来源:发表于2017-05-15 22:09 被阅读169次

Python 解释器碰到特殊的句法时,会使用特殊方法去激活一些基本的对象操作,这些特殊方法的名字以两个下划线开头,以两个下划线结尾(例如__getitem__)。
譬如,当使用len(obj)时,解释器实际会调用obj.__len__
这些特殊方法名能让你自己的对象实现和支持以下的语言构架,并与之交互:

  • 迭代 (__iter__, __reversed__...)
  • 集合类 (__getitem__, __len__ ...)
  • 属性访问 (__getattr__, __setattr__...)
  • 运算符重载 (__lt__, __add__...)
  • 对象的创建和销毁 (__new__, __del__...)
  • 字符串表示形式和格式 (__repr__, __str__...)
  • 管理上下文(即with模块)(__enter__, __exit__)

下面来看一个例子,其中的类实现了2个特殊方法,__len____getitem__

from collections import namedtuple

# 使用命名元组,可以简单的构建一个对象
Card = namedtuple("Card", ["rank", "suit"])


class FrenchDeck:
    # 2-A
    ranks = [str(n) for n in range(2, 11)] + list('JQKA')
    # 4种花色
    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__实现:

>>> deck = FrenchDeck()
>>> len(deck)
52

抽取特定的一张纸牌,由__getitem__实现.

>>> deck[0]
Card(rank='2', suit='spades')

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

# 查看最上面3 张
>>> deck[:3]
[Card(rank='2', suit='spades'), Card(rank='3', suit='spades'),
Card(rank='4', suit='spades')]
# 只看牌面是A 的牌
>>> 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 card in deck: # doctest: +ELLIPSIS
... print(card)
Card(rank='2', suit='spades')
Card(rank='3', suit='spades')
Card(rank='4', suit='spades')
...

迭代通常是隐式的,譬如说一个集合类型没有实现__contains__ 方法,那么in 运算符就会按顺序做一次迭代搜索。

>>> Card('Q', 'hearts') in deck
True
>>> Card('7', 'beasts') in deck
False

从上面的例子可以看出,通过实现__len____getitem__ 这两个特殊方法,FrenchDeck就跟一个Python 自有的序列数据类型一样,可以体现出Python 的核心语言特性(例如迭代和切片)
另外要明确的是,特殊方法的存在是为了被Python解释器调用的,自己并不需要调用它。也就是说没有obj.__len__这种写法,而应该使用len(obj).
然而如果是Python内置类型,譬如列表、字符串、字节序列等,那么CPython会抄近路,__len__实际上会直接返回PyVarObject里的ob_size属性。PyVarObject是表示内存中长度可变的内置对象的C语言结构体,直接读取这个值比调用一个方法快很多。很多时候,特殊方法的调用的是隐式的,比如for i in x:这个语句,背后其实用的是iter(x)。而这个函数的背后则是x.__iter__()方法。
另外,__init__方法外比较特殊,代码里我们可能会经常用到它,目的是在自己的子类__init__方法中调用超类的构造器。

相关文章

  • Fluentpython Python的特殊方法

    Fluentpython 特殊方法 特殊方法的存在是为了被 Python 解释器调用的Python 语言参考手册中...

  • Python10--类中的魔法方法

    1.类中的特殊方法(魔法方法) 在 Python 中有一些特殊的方法,它们是 Python 内置的方法,通常以双下...

  • Python 特殊方法一览

    Python 特殊方法一览 和运算符无关的特殊方法 和运算符相关的特殊方法

  • Python的特殊方法

    Python 解释器碰到特殊的句法时,会使用特殊方法去激活一些基本的对象操作,这些特殊方法的名字以两个下划线开头,...

  • *(扩展)定制类

    用特殊方法定制类 ***********************#特殊方法是Python 中用来扩充类的强有力的方...

  • Python中的特殊方法和语法

    一、Python中特殊方法 1、Python如何把任意类型变量变成str? 因为任意数据类型的实例都有一个特殊方法...

  • python中定制类

    python的特殊方法 特殊方法定义在class中 不需要直接调用 Python的某些函数或者操作符会调用对应的特...

  • 第二章 与Python的无缝集成----基本特殊方法.

    第二章 与Python的悟性陈继承----基本特殊方法. python中有有一些特殊的方法,它们允许我们的类和py...

  • 18、定制类

    18.1python中的特殊方法 1、python能够将任意变量变成str是因为任何数据类型的实例都有一个特殊方法...

  • 一个Java 程序员的python学习之路9- __getite

    python中的和下划线有关的几种特殊方法 Python 中会用到下划线作为变量前缀和后缀指定特殊变量和方法,其中...

网友评论

    本文标题:Python的特殊方法

    本文链接:https://www.haomeiwen.com/subject/hpkkxxtx.html