零散笔记

1

函数式语言通常会提供 map、filter 和 reduce 三个高阶函数(有时使用不同的名称)。在 Python 3 中,map 和 filter 还是内置函数,但是由于引入了列表推导和生成器表达式,它们变得没那么重要了。列表推导或生成器表达式具有 map 和 filter 两个函数的功能,而且更易于阅读。

2

仅限关键字参数是 Python 3 新增的特性。定义函数时若想指定仅限关键字参数,要把它们放到前面有 * 的参数后面。如果不想支持数量不定的定位参数,但是想支持仅限关键字参数,在签名中放一个 *,如下所示:

>>> def f(a, *, b):
...     return a, b
...
>>> f(1, b=2)
(1, 2)

注意,仅限关键字参数不一定要有默认值,可以像上例中 b 那样,强制必须传入实参。
下面看一个实例,生成HTML标签

def tag(name, *content, cls=None, **attrs):
    if cls is not None:
        attrs['class'] = cls
    
    # 将attrs里的内容拼接
    if attrs:
        attrs_str = ' '.join('%s="%s"' % attr for attr in attrs.items() )
    else:
        attrs_str = ''
    
    # 组装一个完整的html标签
    if content:
        return '\n'.join('<%s %s>%s' % (name, attrs_str, c, name) for c in content)
    else:
        return '' % name

# cls是仅限关键字参数,赋值时必须以 参数名=值 的形式
print(tag('a', '采纳', '点赞', cls='btn', href='www.baidu.com'))
"""
采纳
点赞
"""

3

要想创建可散列的类型,不一定要实现特性,也不一定要保护实例属性。只需正确地实现__hash____eq__ 方法即可。但是,实例的散列值绝不应该变化,因此我们借机提到了只读特性。

4

如果使用得当,__slots__ 能显著节省内存,不过有几点要注意。

  • 每个子类都要定义 __slots__ 属性,因为解释器会忽略继承的 __slots__ 属性。

  • 实例只能拥有 __slots__ 中列出的属性,除非把 __dict__ 加入 __slots__ 中(这样做就失去了节省内存的功效)。

  • 如果不把 __weakref__ 加入 __slots__,实例就不能作为弱引用的目标。

5

属性查找失败后,解释器会调用 __getattr__ 方法。简单来说,对 my_obj.x 表达式,Python 会检查 my_obj 实例有没有名为 x 的属性;如果没有,到类(my_obj.__class__)中查找;如果还没有,顺着继承树继续查找。 如果依旧找不到,调用 my_obj 所属类中定义的 __getattr__ 方法,传入 self 和属性名称的字符串形式(如 'x'

6

使用 reduce 函数时最好提供第三个参数,reduce(function, iterable, initializer),这样能避免这个异常:TypeError: reduce() of empty sequence with no initial value(这个错误消息很棒,说明了问题,还提供了解决方法)。如果序列为空,initializer 是返回的结果;否则,在归约中使用它作为第一个参数,因此应该使用恒等值。比如,对 +|^ 来说, initializer 应该是 0;而对 *& 来说,应该是 1

7

如果没有 __iter____contains__ 方法,Python 会调用 __getitem__ 方法,设法让迭代和 in 运算符可用。

8

猴子补丁

import collections

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()

    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类还不能使用random.shuffle 函数随意打乱集合中元素的位置,因为FrenchDeck 只实现了不可变的序列协议。可变的序列还必须提供 __setitem__ 方法。
下面在控制台进行修正

>>> def set_card(deck, position, card): 
...     deck._cards[position] = card
...
>>> FrenchDeck.__setitem__ = set_card 
>>> shuffle(deck) 
>>> deck[:5]
[Card(rank='3', suit='hearts'), Card(rank='4', suit='diamonds'), Card(rank='4',
suit='clubs'), Card(rank='7', suit='hearts'), Card(rank='9', suit='spades')]

特殊方法 __setitem__的签名在 Python 语言参考手册的“3.3.6. Emulating container types”中定义。语言参考中使用的参数是 selfkeyvalue

你可能感兴趣的:(零散笔记)