《流畅的Python》学习笔记(2) —— 数据模型

1. 一致性

所谓一致性,我的理解是相类似的东西应该使用相同的方法,例如Python中序列的长度都可以使用len()方法进行处理,字符串的拼接可以使用“+”号来统一实现,这就是一致性的实际案例。那么这种一致性是如何是实现的?

2.数据模型

数据模型其实是对 Python 框架的描述,它规范了这门语言自身构建模块的接口,这些模块包括但不限于序列、迭代器、函数、类和上下文管理器,可以说是Python的基类(object)定义。

Python 解释器碰到特殊的句法时,会使用特殊方法去激活一些基本的对象操作,这些特殊方法的名字以两个下划线开头。例如obj[key]其实python调用的方法是__getitem__方法。

3.案例:一副扑克牌

可以用一个有趣的例子体现数据模型的作用。

需求:定义一副扑克牌,扑克牌有花色和点数两种属性。
import doctest
import collections
# namedtuple是python中一种只定义了属性没有定义方法的类,类似于Java中的Java Bean
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()
    # 字符串默认以‘ ’space进行分割

    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, index):
        return self._cards[index]

上述的代码已经可以实现一副简单的扑克牌序列的效果,运行代码可以得到

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

>>> deck[0]
Card(rank='2', suit='spades')
>>> deck[-1]
Card(rank='A', suit='hearts')

>>> from random import choice
>>> choice(deck)
Card(rank='3', suit='hearts')
>>> choice(deck)
Card(rank='K', suit='spades')
>>> choice(deck)
Card(rank='2', suit='clubs')

从这个案例中,Python的数据模型可以有两种好处。

  • 统一的API调用方法,比如len()方法
  • 可以利用标准库的的方法,不用重新造轮子

比如random.choice函数可以直接利用到上面。

>>> from random import choice
>>> choice(deck)
Card(rank='3', suit='hearts')
>>> choice(deck)
Card(rank='K', suit='spades')
>>> choice(deck)
Card(rank='2', suit='clubs')

4. 测试技术

4.1 doctest

在《流畅的python》常常将doctest作为代码的测试工具,其中很多框架的用例也是经常用doctest作为测试,例如Pytorch中经常会把测试用例写在文档中,既能够方便用户了解API的使用,又能够进行检测,例如:

class Linear(Module):
    r"""Applies a linear transformation to the incoming data: :math:`y = xA^T + b`

    Args:
        in_features: size of each input sample
        out_features: size of each output sample
        bias: If set to ``False``, the layer will not learn an additive bias.
            Default: ``True``

    Shape:
        - Input: :math:`(N, *, H_{in})` where :math:`*` means any number of
          additional dimensions and :math:`H_{in} = \text{in\_features}`
        - Output: :math:`(N, *, H_{out})` where all but the last dimension
          are the same shape as the input and :math:`H_{out} = \text{out\_features}`.

    Attributes:
        weight: the learnable weights of the module of shape
            :math:`(\text{out\_features}, \text{in\_features})`. The values are
            initialized from :math:`\mathcal{U}(-\sqrt{k}, \sqrt{k})`, where
            :math:`k = \frac{1}{\text{in\_features}}`
        bias:   the learnable bias of the module of shape :math:`(\text{out\_features})`.
                If :attr:`bias` is ``True``, the values are initialized from
                :math:`\mathcal{U}(-\sqrt{k}, \sqrt{k})` where
                :math:`k = \frac{1}{\text{in\_features}}`

    Examples::

        >>> m = nn.Linear(20, 30)
        >>> input = torch.randn(128, 20)
        >>> output = m(input)
        >>> print(output.size())
        torch.Size([128, 30])
    """

在Examples中部分就是测试用的代码,也可以用作用户看API使用案例,一举两得。

4.2 doctest使用方法

doctest使用方法可以分为在源代码内和再源代码外写入。

源代码内

直接在代码的注释中,注意是在文档中使用这些测试,具体到代码需要加入:
‘>>>‘表示输入
输入后没有’>>>'为期望输出

class Vector:
	"""This is the object of a vector
	>>> vec = Vector(1,3)
	>>> print(vec)
	Vector(1, 3)
	"""
	def __init__(self, x=0, y=0):
		self.x = x
		self.y = y
	def __repr__(self):
		return 'Vector(%r, %r)' % (self.x, self.y)	

当需要测试时,使用:

if __name__ == '__main__':
    import doctest
    doctest.testmod()

没有错误就没有问题抛出

源代码外

直接将命令行的代码写到文本文件如(testfile)中,而后调用

python -m doctest -f testfile.txt

测试文件样例

>>> from card_set import FrenchDeck, Card
>>> beer_card = Card('7', 'diamonds')
>>> beer_card
Card(rank='7', suit='diamonds')
>>> deck = FrenchDeck()
>>> len(deck)
52
>>> 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')]
>>> Card('Q', 'hearts') in deck
True
发布了4 篇原创文章 · 获赞 2 · 访问量 153

猜你喜欢

转载自blog.csdn.net/baidu_34912627/article/details/104009610