2010-02-10 8 views
8

W python jest możliwe, aby powyższy kod bez podnoszenia wyjątku?Czy można zadeklarować funkcję bez argumentów, a następnie przekazać niektóre argumenty do tej funkcji bez zgłaszania wyjątku?

def myfunc(): 
    pass 

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

Zwykle w php w niektórych okolicznościach uruchamiam funkcję bez parametrów, a następnie odtwarzam parametry wewnątrz funkcji.

W praktyce nie chcę zadeklarować argumentów w myfunc, a następnie przekazać do niego kilka argumentów. Jedyne znalezione rozwiązanie to myfunc(*arg). Czy są jakieś inne metody?

+9

Dlaczego 'myfunc (* arg)' nie wystarczająco dobry? – interjay

+3

Zgaduję, że Yuri (jeszcze) nie wie o * arg – Dana

+0

Implementacja wymaga, aby myfunc był wywołaniem zwrotnym do innej funkcji, która spróbuje wywołać ją w zrozumieniu listy przekazując argumenty. Tak więc nie mam kontroli nad implementacją wywołania zwrotnego i użytkownik nie może - umyślnie ominąć "* args" (w kodzie dbam o to wydarzenie). – yuri

Odpowiedz

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 

I rzeczywiście odpowiedzieć na pytanie: nie, nie wierzę, że istnieją inne sposoby.

Główny powód jest całkiem prosty: C pyton jest oparty na stosie. Funkcja, która nie wymaga parametrów, nie będzie mieć przydzielonego miejsca na stosie (myFunc, zamiast tego ma je w pozycjach 0 i 1). (patrz komentarze)

Dodatkowym punktem jest, w jaki sposób uzyskałbyś dostęp do parametrów w inny sposób?

+2

Komentarz stosu jest poza punktem. Python jest oparty na stosach, ale przekazywanie argumentów (i parsowanie) nie jest (argumenty są zawsze pojedynczym elementem na stosie, nawet jeśli nie ma żadnych argumentów). Powodem, dla którego Python nie ignoruje argumentów, jest ** ukrywanie błędów. **. –

+0

Jest to całkiem możliwe, że błędnie odczytuję to, co mi powiedziałem :) – badp

4

Pewnie można!

Można zdefiniować zmienne listy parametrów długość tak:

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

args jest krotką swoimi parametrami więc wywołanie:

foo(1,2) 

daje krotki (1, 2) wewnątrz funkcji .

+0

'args' będzie w rzeczywistości krotką. –

+0

O tak! Naprawiony! – Dana

11

Istnieją dwa sposoby, aby zdać args w

By Pozycja

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

Według słowa

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

I można użyć kombinację obu

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

Oto funkcja dekorator pisałem właśnie do tego, wraz z przykładem użycia:

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