@Pythonetc 2018年11月







これは、私の@pythonetcフィードからのPythonのヒントとプログラミングの6番目のコレクションです。



以前の選択:







非定型デコレータ



関数デコレータは新しい関数のみを返す必要はなく、他の値を返すことができます。



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
      
      





これは、再定義可能なメソッドを1つだけ持つ単純なクラスを作成するのに役立ちます。



 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__



を使用し__len__



。 反復可能なオブジェクトを使用していて、その長さを知りたい場合は、 operator.length_hint



使用しoperator.length_hint







ジェネレーターで



in



演算子はジェネレーターで使用できます: x in g



。 この場合、Pythonはx



g



終了するまでg



を反復処理します。



 >>> 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には、2つの異なる演算子+=



+



ます。 __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



ます。



+=



+



のセマンティックの違いは、最初のオブジェクトがオブジェクトを変更し、2番目のオブジェクトが新しいオブジェクトを作成することです。



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






All Articles