@Pythonetc 2018年11月


这是来自@pythonetc feed的第六个Python技巧和编程集合。

先前的选择:



非典型装饰


不需要函数装饰器仅返回新函数,它们可以返回任何其他值:

def call(*args, **kwargs): def decorator(func): return func(*args, **kwargs) return decorator @call(15) def sqr_15(x): return x * x assert sqr_15 == 225 

这对于仅使用一种可重新定义的方法创建简单的类很有用:

 from abc import ABCMeta, abstractmethod class BinaryOperation(metaclass=ABCMeta): def __init__(self, left, right): self._left = left self._right = right def __repr__(self): klass = type(self).__name__ left = self._left right = self._right return f'{klass}({left}, {right})' @abstractmethod def do(self): pass @classmethod def make(cls, do_function): return type( do_function.__name__, (BinaryOperation,), dict(do=do_function), ) class Addition(BinaryOperation): def do(self): return self._left + self._right @BinaryOperation.make def Subtraction(self): return self._left - self._right 


__length_hint__


PEP 424允许没有特定预定大小的生成器和其他可迭代程序返回其近似长度。 例如,此生成器可能会返回大约50个元素:

 (x for x in range(100) if random() > 0.5) 

如果您编写了可迭代的东西并想返回一个近似的长度,请定义__length_hint__方法。 如果知道确切的长度,请使用__len__ 。 如果使用可迭代对象,并且想知道它可以持续多久,请使用operator.length_hint

与发电机一起


in运算符可以与生成器一起使用: x in g 。 在这种情况下,Python将遍历g直到xg结束。

 >>> def g(): ... print(1) ... yield 1 ... print(2) ... yield 2 ... print(3) ... yield 3 ... >>> 2 in g() 1 2 True 

range()不过效果更好。 它具有不可思议的覆盖方法__contains__ ,因此in的计算复杂度等于O(1):

 In [1]: %timeit 10**20 in range(10**30) 375 ns ± 10.7 ns per loop 

请注意,这不适用于Python 2中的xrange()函数。

运算符+ =和+


Python有两个不同的运算符: +=+__iadd____add__方法分别负责它们的行为。

 class A: def __init__(self, x): self.x = x def __iadd__(self, another): self.x += another.x return self def __add__(self, another): return type(self)(self.x + another.x) 

如果__iadd__ ,则a += b将作为a = a + b起作用。

+=+之间的语义区别在于,第一个更改对象,而第二个创建新对象:

 >>> a = [1, 2, 3] >>> b = a >>> a += [4] >>> a [1, 2, 3, 4] >>> b [1, 2, 3, 4] >>> a = a + [5] >>> a [1, 2, 3, 4, 5] >>> b [1, 2, 3, 4] 

用作类的属性


您不能将函数存储为类属性,因为如果通过实例访问它,它将自动转换为方法:

 >>> class A: ... CALLBACK = lambda x: x ** x ... >>> A.CALLBACK <function A.<lambda> at 0x7f68b01ab6a8> >>> A().CALLBACK <bound method A.<lambda> of <__main__.A object at 0x7f68b01aea20>> >>> A().CALLBACK(4) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: <lambda>() takes 1 positional argument but 2 were given 

您可以将函数作弊并包装在一个简单的描述符中:

 >>> class FunctionHolder: ... def __init__(self, f): ... self._f = f ... def __get__(self, obj, objtype): ... return self._f ... >>> class A: ... CALLBACK = FunctionHolder(lambda x: x ** x) ... >>> A().CALLBACK <function A.<lambda> at 0x7f68b01ab950> 

您也可以使用类方法而不是属性来摆脱这种情况。

 class A: @classmethod def _get_callback(cls): return lambda x: x ** x 

Source: https://habr.com/ru/post/zh-CN432628/


All Articles