2011-10-18 14 views
25

Básicamente, lo que me gustaría hacer es:¿Cómo rellenar argumentos posicionales específicos con parcial en python?

>>> from functools import partial 
>>> partial(str.startswith, prefix='a')('a') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: startswith() takes no keyword arguments 

Pero en términos más generales, la pregunta es cómo llenar argumentos posicionales específicos con partial.

P.S. Me doy cuenta de que puedo usar un lambda en su lugar.

+1

seguir adelante y utilizar 'lambda'. Será un poco más lento porque 'partial' se implementa en C. Si el rendimiento es una prima, también puede implementar su variante en C. – wberry

Respuesta

32

No se puede hacer. Tienes que hacer una función de envoltura.

Aparentemente, usaría argumentos de palabras clave, como lo intentó hacer, para eso están, ¿no? Desafortunadamente, como ha descubierto, la biblioteca estándar de Python funciona do not take named parameters. Por lo tanto, no es posible dada la implementación actual de partial sin hacer otra función para ejecutar interferencias.

De acuerdo con la aceptación de PEP 309, lo que fue aceptado para su inclusión fue "un parcial() de tipo constructor de unión más a la izquierda argumentos posicionales y las palabras clave". Además, se indica:

Tenga en cuenta que cuando el objeto se llama como si se tratara de una función, argumentos posicionales son anexa a los previstos para el constructor, y los argumentos de palabras clave anulan y aumentan los proporcionados al constructor.

Los argumentos de posición, los argumentos de palabra clave o ambos se pueden proporcionar al crear el objeto y al llamarlo.

Debido argumentos posicionales adicionales se anexan, no habría manera de suministrar un argumento posicional precedente (por esta aplicación).

Sin embargo, continúa:

argumentos se aplican parcialmente de la derecho, o la inserción de argumentos en posiciones arbitrarias crea sus propios problemas, pero en espera de descubrimiento de una buena aplicación y no confundiendo la semántica No creo que deba descartarse.

Por lo tanto, aparentemente podría estar sobre la mesa, pero tal como está, no está implementado de esa manera.

Por el bien de la divulgación, el énfasis en las citas anteriores fue mío.

0

Usar este código:

# See: functoolspartial for binding... 

class Function(object): 
    def __init__(self, fn): 
     self.fn = fn 

    def __call__(self, *args, **kwargs): 
     return self.fn(*args, **kwargs) 

    def __add__(self, other): 
     def subfn(*args, **kwargs): 
      return self(*args, **kwargs) + other(*args, **kwargs) 
     return subfn 


class arg(object): 
    """Tagging class""" 
    def __init__(self, index): 
     self.index = index 


class bind(Function): 
    """Reorder positional arguments. 
    Eg: g = f('yp', _1, 17, _0, dp=23) 
    Then g('a', 'b', another=55) --> f('yp', 'b', 17, 'a', dp=23, another=55) 
    """ 

    def __init__(self, fn, *pargs, **pkwargs): 
     # Maximum index referred to by the user. 
     # Inputs to f above this index will be passed through 
     self.fn = fn 
     self.pargs = pargs 
     self.pkwargs = pkwargs 
     self.max_gindex = max(
      (x.index if isinstance(x, arg) else -1 for x in pargs), 
      default=-1) 

    def __call__(self, *gargs, **gkwargs): 
     fargs = \ 
      [gargs[x.index] if isinstance(x, arg) else x for x in self.pargs] + \ 
      list(gargs[self.max_gindex+1:]) 

     fkwargs = dict(self.pkwargs) 
     fkwargs.update(gkwargs) # Overwrite keys 
     return self.fn(*fargs, *fkwargs) 

luego probarlo hacia fuera como:

def myfn(a,b,c): 
print(a,b,c) 

bind(myfn, arg(1), 17, arg(0))(19,14) 
3

Si realmente necesita esta puede utilizar rpartial de funcy biblioteca de tercera parte.

Su código está aquí:

def rpartial(func, *args): 
    return lambda *a: func(*(a + args)) 

lo tanto, su caso puede ser manejado de la siguiente manera:

>>> startswith_a = rpartial(str.startswith, 'a') 
>>> startswith_a('abc') 
True 
>>> startswith_a('def') 
False 
Cuestiones relacionadas