@Pythonetc novembre 2018


Ceci est la sixiĂšme collection de conseils et de programmation Python de mon flux @pythonetc.

Sélections précédentes:



DĂ©corateurs atypiques


Les décorateurs de fonctions ne sont pas tenus de renvoyer uniquement de nouvelles fonctions, ils peuvent renvoyer toute autre valeur:

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 

Cela peut ĂȘtre utile pour crĂ©er des classes simples avec une seule mĂ©thode redĂ©finissable:

 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__


Le PEP 424 permet aux générateurs et autres itérables qui n'ont pas de taille prédéterminée spécifique de renvoyer leur longueur approximative. Par exemple, ce générateur retournera probablement environ 50 éléments:

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

Si vous Ă©crivez quelque chose d'itĂ©rable et que vous souhaitez renvoyer une longueur approximative, dĂ©finissez la mĂ©thode __length_hint__ . Et si vous connaissez la longueur exacte, utilisez __len__ . Si vous utilisez un objet itĂ©rable et que vous voulez savoir combien de temps il peut ĂȘtre, utilisez operator.length_hint .

avec générateur


L'opĂ©rateur in peut ĂȘtre utilisĂ© avec des gĂ©nĂ©rateurs: x in g . Dans ce cas, Python itĂ©rera sur g jusqu'Ă  ce que x ou jusqu'Ă  ce que g se termine.

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

range() , cependant, fonctionne légÚrement mieux. Il a une méthode magique __contains__ , grùce à laquelle la complexité de calcul de in devient égale à O (1):

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

Notez que cela ne fonctionnera pas avec la fonction xrange() de Python 2.

Opérateurs + = et +


Python a deux opérateurs différents: += et + . Les méthodes __iadd__ et __add__ sont respectivement responsables de leur comportement.

 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) 

Si __iadd__ pas défini, alors a += b fonctionnera comme a = a + b .

La différence sémantique entre += et + est que le premier change l'objet, et le second en crée un nouveau:

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

Fonction comme attribut d'une classe


Vous ne pouvez pas stocker une fonction en tant qu'attribut de classe, car elle sera automatiquement convertie en méthode si elle est accessible via une instance:

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

Vous pouvez tricher et encapsuler la fonction dans un descripteur trivial:

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

Vous pouvez également sortir de la situation en utilisant la méthode de classe au lieu de l'attribut.

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

Source: https://habr.com/ru/post/fr432628/


All Articles