Pregunta

Estoy emocionado de ver la última versión del módulo de decorator pitón (3,0). Se ve mucho más limpio (por ejemplo, la sintaxis es más dulce que nunca) de iteraciones anteriores.

Sin embargo, parece tener el apoyo pésimo (por ejemplo, la sintaxis "amargo", para estirar la metáfora horrible) para decoradores que toman argumentos a sí mismos. ¿Alguien tiene un buen ejemplo de la forma en que te limpia hace esto usando <=> 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
¿Fue útil?

Solución

En este caso, usted necesita para hacer su función de retorno del decorador. (Cualquier cosa puede ser resuelto por otro nivel de indirección ...)

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

Esto significa substitute_args no es un decorador en sí, es un decorador fábrica . Aquí está el equivalente sin la decorator módulo.

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

tres niveles de profundidad no es muy conveniente, pero recuerda que dos de ellos son cuando se define la función:

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

Lo cual es equivalente a:

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

Otros consejos

aquí hay otra manera de que me acaban de descubrir: comprobar si el primer (y único) argumento para su decorador es exigible; Si es así, ya está resuelto y puede devolver su método de envoltura modifiquen su comportamiento (sí decoradas con functools.wraps para preservar el nombre y la documentación de cadena).

en el otro caso, uno o más nombrado o argumentos posicionales deben estar presentes; puede obtener esos argumentos y devolver una exigible que acepta un exigible como primer argumento y devuelve un método de envoltura y desde esa descripción se ajusta a la descripción del método decorador, retorno que método muy decorador! que he usado functools.partial aquí para obtener una versión de mi decorador, is_global_method (que estoy trabajando en este momento, su aplicación es de sentido supuesto, como se muestra a continuación, esto es sólo para demostrar los trabajos de acabado).

esta solución parece funcionar pero seguro necesita más pruebas. si Quint nuestros ojos, se puede ver que el truco es de sólo tres o cuatro líneas como un patrón para recordar. Ahora me pregunto si puedo envolver ese tipo de funcionalidad en otro decorador? ah, el metaness de ella!

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 ) )
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top