2010-02-10 10 views
8

En python, ¿es posible tener el código anterior sin generar una excepción?¿Es posible declarar una función sin argumentos pero luego pasar algunos argumentos a esa función sin aumentar la excepción?

def myfunc(): 
    pass 

# TypeError myfunc() takes no arguments (1 given) 
myfunc('param') 

Por lo general, en php en algunas circunstancias lanzo una función sin parámetros y luego recuperar los parámetros dentro de la función.

En la práctica, no quiero declarar argumentos en myfunc y luego pasarle algunos argumentos. La única solución que encontré es myfunc(*arg). ¿Hay algún otro método?

+9

¿Por qué es 'myfunc (* arg)' no es suficiente? – interjay

+3

Supongo que yuri todavía no (sabe) sobre * arg – Dana

+0

La implementación necesita que myfunc sea una devolución de llamada pasada a otra función que intente llamarlo en una lista de comprensión pasando un argumento. Así que no tengo control sobre la implementación de devolución de llamada y el usuario no puede omitir intencionalmente el '* args' (en el código me ocupo de este evento) – yuri

Respuesta

10
>>> def myFunc(*args, **kwargs): 
... # This function accepts arbitary arguments: 
... # Keywords arguments are available in the kwargs dict; 
... # Regular arguments are in the args tuple. 
... # (This behaviour is dictated by the stars, not by 
... # the name of the formal parameters.) 
... print args, kwargs 
... 
>>> myFunc() 
() {} 
>>> myFunc(2) 
(2,) {} 
>>> myFunc(2,5) 
(2, 5) {} 
>>> myFunc(b = 3) 
() {'b': 3} 
>>> import dis 
>>> dis.dis(myFunc) 
    1   0 LOAD_FAST    0 (args) 
       3 PRINT_ITEM 
       4 LOAD_FAST    1 (kwargs) 
       7 PRINT_ITEM 
       8 PRINT_NEWLINE 
       9 LOAD_CONST    0 (None) 
      12 RETURN_VALUE 

Y para responder a la cuestión de hecho: no, no creo que hay otras maneras.

La razón principal es bastante simple: C python se basa en la pila. Una función que no requiere parámetros no tendrá espacio asignado en la pila (myFunc, en cambio, los tiene en la posición 0 y 1). (ver comentarios)

Un punto adicional es, ¿cómo accederías a los parámetros de lo contrario?

+2

El comentario de la pila es además del punto. Python se basa en la pila, pero el argumento que pasa (y el análisis) no lo es (los argumentos son siempre un solo elemento en la pila, incluso cuando no hay argumentos). La razón por la cual Python no ignora los argumentos es porque ** oculta los errores **. –

+0

Es muy posible que esté malinterpretando lo que dis me dice :) – badp

4

¡Claro!

Puede definir una lista de parámetros de longitud variable, así:

def foo(*args): 
    print len(args) 

args es una tupla de sus parámetros así que llamar:

foo(1,2) 

le da la tupla (1, 2) dentro de su función .

+0

'args' en realidad será una tupla. –

+0

¡Oh, sí! ¡Fijo! – Dana

11

Hay dos formas de pasar argumentos en

por Posición

>>> def myfunc(*args): 
... print "args", args 
... 
>>> myfunc("param") 
args ('param',) 

por Palabra clave

>>> def myfunc(**kw): 
... print "kw", kw 
... 
>>> myfunc(param="param") 
kw {'param': 'param'} 

y se puede utilizar una combinación de ambos

>>> def myfunc(*args, **kw): 
... print "args", args 
... print "kw", kw 
... 
>>> myfunc("param") 
args ('param',) 
kw {} 
>>> 
>>> myfunc(param="param") 
args() 
kw {'param': 'param'} 
>>> 
>>> myfunc("param", anotherparam="anotherparam") 
args ('param',) 
kw {'anotherparam': 'anotherparam'} 
1

Aquí es un decorador de la función que escribí para hacer precisamente eso, junto con un ejemplo de uso:

def IgnoreExtraArguments(f): 
    import types 
    c = f.func_code 
    if c.co_flags & 0x04 or c.co_flags&0x08: 
     raise ValueError('function already accepts optional arguments') 
    newc = types.CodeType(c.co_argcount, 
        c.co_nlocals, 
        c.co_stacksize, 
        c.co_flags | 0x04 | 0x08, 
        c.co_code, 
        c.co_consts, 
        c.co_names, 
        c.co_varnames+('_ignore_args','_ignore_kwargs'), 
        c.co_filename, 
        c.co_name, 
        c.co_firstlineno, 
        c.co_lnotab, 
        c.co_freevars, 
        c.co_cellvars) 
    f.func_code = newc 
    return f 

if __name__ == "__main__": 
    def f(x,y): 
     print x+y 

    g = IgnoreExtraArguments(f) 
    g(2,4) 
    g(2,5,'banana') 

    class C(object): 
     @IgnoreExtraArguments 
     def m(self,x,y): 
      print x-y 

    a=C() 
    a.m(3,5) 
    a.m(3,6,'apple') 
Cuestiones relacionadas