Question

Je suis très heureux de voir la dernière version du module python decorator (3.0). Il semble beaucoup plus propre (par exemple, la syntaxe est plus sucrée que jamais) que les précédentes itérations.

Cependant, il semble avoir un soutien moche (par exemple la syntaxe « aigre », d'étirer horriblement la métaphore) pour les décorateurs qui prennent eux-mêmes arguments. Quelqu'un at-il un bon exemple pour la façon dont vous souhaitez le faire en utilisant proprement 3.0 <=>?

 def substitute_args(fun, arg_sub_dict):
      def wrapper(arg):
         new_arg = arg_sub_dict.get(arg, arg)
         return fun(new_arg)

      # some magic happens here to make sure that type signature, 
      # __name__, __doc__, etc. of wrapper matches fun

 return wrapper
Était-ce utile?

La solution

Dans ce cas, vous devez faire de votre fonction retourne le décorateur. (Tout peut être résolu par un autre niveau d'indirection ...)

from decorator import decorator
def substitute_args(arg_sub_dict):
  @decorator
  def wrapper(fun, arg):
    new_arg = arg_sub_dict.get(arg, arg)
    return fun(new_arg)
  return wrapper

Cela signifie n'est pas un substitute_args décorateur lui-même, il est un décorateur usine . Voici l'équivalent sans le module decorator.

def substitute_args(arg_sub_dict):
  def my_decorator(fun):
    def wrapper(arg):
      new_arg = arg_sub_dict.get(arg, arg)
      return fun(new_arg)
    # magic to update __name__, etc.
    return wrapper
  return my_decorator

profonde est pas très pratique Trois niveaux, mais rappelez-vous deux d'entre eux sont quand la fonction est définie:

@substitute_args({}) # this function is called and return value is the decorator
def f(x):
  return x
# that (anonymous) decorator is applied to f

Ce qui est équivalent à:

def f(x):
  return x
f = substitude_args({})(f) # notice the double call

Autres conseils

Voici une autre façon que je viens de découvrir: vérifier si le premier (et seul) argument à votre décorateur est appelable; si oui, vous avez terminé et pouvez retourner votre méthode d'emballage modifiant leur comportement (lui-même décoré de conserver le nom functools.wraps et chaîne documentation).

dans l'autre cas, un ou plusieurs arguments nommés ou de position doivent être présents; vous pouvez recueillir ces arguments et renvoyer une appelable qui accepte un appelable comme premier argument et retourne une méthode et emballage depuis cette description correspond à la description de la méthode de décorateur, retour que méthode très décorateur! Je l'ai utilisé ici pour obtenir functools.partial une version de mon décorateur, is_global_method (qui je travaille en ce moment-sa mise en œuvre est évidemment absurde, comme indiqué ci-dessous, ce n'est de montrer les œuvres de décoration).

cette solution semble fonctionner, mais a besoin que d'autres tests. si vous QUINT nos yeux, vous pouvez voir que l'astuce est seulement trois ou quatre lignes comme un modèle à retenir. Maintenant, je me demande si je peux conclure ce genre de fonctionnalité dans un autre décorateur? ah, le metaness de celui-ci!

from functools import wraps
from functools import partial

_               = print
is_instance_of  = isinstance
is_callable     = lambda x: hasattr( x, '__call__' )

def is_global_method( x, *, name = None ):
  if is_callable( x ):
    @wraps( x )
    def wrapper( *P, **Q ):
      return { 'name': name, 'result': x( *P, **Q ), }
    return wrapper
  # assert is_instance_of( x, str ) # could do some sanity checks here
  return partial( is_global_method, name = x )

@is_global_method
def f( x ):
  """This is method f."""
  return x ** 2

@is_global_method( 'foobar' )
def g( x ):
  """This is method g."""
  return x ** 2

_( f.__name__ )
_( f.__doc__ )
_( f( 42 ) )
_( g.__name__ )
_( g.__doc__ )
_( g( 42 ) )
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top