Czy Można zadeklarować funkcję w Pythonie?

Czy Można zadeklarować funkcję w Pythonie? Chcę posortować listę używając mojej własnej funkcji cmp, zanim zostanie zadeklarowana.

print "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)])

Uporządkowałem swój kod tak, aby po wywołaniu umieścić definicję metody cmp_configs. Nie powiodło się z tym błędem:

NameError: name 'cmp_configs' is not defined

Czy jest jakiś sposób, aby" zadeklarować " cmp_configs metodę przed jej użyciem? To sprawi, że mój kod będzie wyglądał czystiej?

Zakładam, że niektórzy ludzie będą kuszeni, aby powiedzieć mi, że powinienem po prostu zreorganizować moją kod, żebym nie miał tego problemu. Są jednak przypadki, gdy jest to prawdopodobnie nieuniknione, na przykład podczas implementacji niektórych form rekurencji. Jeśli nie podoba Ci się ten przykład, załóżmy, że mam przypadek, w którym jest naprawdę konieczne forward zadeklarować funkcję.

Rozważ ten przypadek, w którym forward-deklarowanie funkcji byłoby konieczne w Pythonie:

def spam():
    if end_condition():
        return end_result()
    else:
        return eggs()

def eggs():
    if end_condition():
        return end_result()
    else:
        return spam()

Gdzie end_condition i end_result zostały wcześniej zdefiniowane.

Jest jedynym rozwiązaniem przeorganizować kod i zawsze stawiać definicje przed wywołaniami?

Author: Eric Leschinski, 2009-10-19

17 answers

Jeśli nie chcesz definiować funkcji przed użyciem, a zdefiniowanie jej później jest niemożliwe, co powiesz na zdefiniowanie jej w innym module?

Formalnie nadal definiujesz to jako pierwsze, ale jest czyste.

Możesz utworzyć rekurencję w następujący sposób:

def foo():
    bar()

def bar():
    foo()

Funkcje Pythona są Anonimowe, podobnie jak wartości są anonimowe, ale mogą być powiązane z nazwą.

W powyższym kodzie foo() nie wywołuje funkcji o nazwie foo, wywołuje funkcję, która jest powiązana z nazwą foo w momencie wywołania. Możliwe jest ponowne zdefiniowanie foo gdzie indziej, a bar wywoła nową funkcję.

Twój problem nie może zostać rozwiązany, ponieważ to jak prośba o podanie zmiennej, która nie została zadeklarowana.

 79
Author: RichN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-27 00:20:59

To, co możesz zrobić, to zawinąć wywołanie w własną funkcję.

Tak, że

foo()

def foo():
    print "Hi!"

Złamie się, ale

def bar():
    foo()

def foo():
    print "Hi!"

bar()

Będzie działać poprawnie.

Ogólna zasada w Pythonto nie , że funkcja powinna być zdefiniowana wyżej w kodzie (jak w Pascal), ale powinna być zdefiniowana przed jej użyciem.

Mam nadzieję, że to pomoże.
 132
Author: Vanya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-02 15:30:35

Jeśli uruchomisz skrypt poprzez:

if __name__=="__main__":
   main()

Wtedy prawdopodobnie nie musisz się martwić o rzeczy takie jak"forward declaration". Widzisz, interpreter załaduje wszystkie twoje funkcje, a następnie uruchomi funkcję main (). Oczywiście upewnij się, że wszystkie importy są poprawne; -)

Nigdy nie słyszałem czegoś takiego jak" forward declaration " w Pythonie... ale z drugiej strony mogę się mylić; -)
 98
Author: jldupont,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-19 19:33:53

Jeśli wywołanie cmp_configs znajduje się wewnątrz jego własnej definicji funkcji, powinno być dobrze. Podam przykład.

def a():
  b()  # b() hasn't been defined yet, but that's fine because at this point, we're not
       # actually calling it. We're just defining what should happen when a() is called.

a()  # This call fails, because b() hasn't been defined yet, 
     # and thus trying to run a() fails.

def b():
  print "hi"

a()  # This call succeeds because everything has been defined.

Ogólnie rzecz biorąc, umieszczenie kodu wewnątrz funkcji (takich jak main ()) rozwiąże problem; wystarczy wywołać main () na końcu pliku.

 11
Author: BJ Homer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-19 19:38:52

W Pythonie nie ma czegoś takiego jak deklaracja forward. Musisz tylko upewnić się, że twoja funkcja jest zadeklarowana, zanim będzie potrzebna. Zauważ, że ciało funkcji nie jest interpretowane dopóki funkcja nie zostanie wykonana.

Rozważ następujący przykład:

def a():
   b() # won't be resolved until a is invoked.

def b(): 
   print "hello"

a() # here b is already defined so this line won't fail.

Możesz myśleć, że ciało funkcji jest tylko kolejnym skryptem, który zostanie zinterpretowany po wywołaniu funkcji.

 10
Author: Piotr Czapla,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-19 19:42:13

Przepraszam za ożywienie tego wątku, ale nie była tu omawiana strategia, która może mieć zastosowanie.

Używając reflection można zrobić coś podobnego do forward declaration. Na przykład powiedzmy, że masz sekcję kodu, która wygląda tak:

# We want to call a function called 'foo', but it hasn't been defined yet.
function_name = 'foo'
# Calling at this point would produce an error

# Here is the definition
def foo():
    bar()

# Note that at this point the function is defined
    # Time for some reflection...
globals()[function_name]()

Więc w ten sposób ustaliliśmy, jaką funkcję chcemy wywołać, zanim zostanie ona faktycznie zdefiniowana, czyli deklaracja forward. W Pythonie wyrażenie globals()[function_name]() jest takie samo jak foo() if function_name = 'foo' z powodów omówione powyżej, ponieważ python musi przeszukać każdą funkcję przed jej wywołaniem. Jeśli ktoś użyje modułu timeit, aby zobaczyć, jak te dwa stwierdzenia się porównują, mają dokładnie taki sam koszt obliczeniowy.

Oczywiście przykład tutaj jest bardzo bezużyteczny, ale jeśli ktoś ma mieć złożoną strukturę, która wymaga wykonania funkcji, ale musi być zadeklarowana przed (lub strukturalnie nie ma sensu mieć ją później), można po prostu zapisać łańcuch znaków i spróbować wywołać funkcję później.

 10
Author: KGardevoir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-22 04:08:36

Nie, Nie wydaje mi się, aby w Pythonie można było zadeklarować funkcję forward-declare.

Wyobraź sobie, że jesteś interpreterem Pythona. Kiedy dojdziesz do linii

print "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)])

Albo wiesz czym jest cmp_configs, albo nie. aby kontynuować, musisz poznaj cmp_configs. Nie ma znaczenia, czy istnieje rekurencja.

 7
Author: unutbu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-19 19:37:31

Czasami algorytm najłatwiej zrozumieć odgórnie, zaczynając od ogólnej struktury i wnikając w szczegóły.

Możesz to zrobić bez deklaracji forward:

def main():
  make_omelet()
  eat()

def make_omelet():
  break_eggs()
  whisk()
  fry()

def break_eggs():
  for egg in carton:
    break(egg)

# ...

main()
 7
Author: funroll,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-29 10:37:36
# declare a fake function (prototype) with no body
def foo(): pass

def bar():
    # use the prototype however you see fit
    print(foo(), "world!")

# define the actual function (overwriting the prototype)
def foo():
    return "Hello,"

bar()

Wyjście:

Hello, world!
 5
Author: jmurphy61,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-04-29 19:32:15

Importuj sam plik. Zakładając, że plik nazywa się test.py:

import test

if __name__=='__main__':
    test.func()
else:
    def func():
        print('Func worked')
 4
Author: user10488833,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-11 09:20:08

Nie możesz zadeklarować funkcji w Pythonie. Jeśli masz uruchamianie logiczne przed zdefiniowaniem funkcji, prawdopodobnie i tak masz problem. Umieść swoją akcję w if __name__ == '__main__' na końcu skryptu (wykonując funkcję, którą nazwałeś "main", jeśli nie jest trywialna), a Twój kod będzie bardziej modułowy i będziesz mógł go używać jako modułu, jeśli kiedykolwiek będziesz potrzebował.

Również zastąp tę listę wyrażeniem generatora (tj., print "\n".join(str(bla) for bla in sorted(mylist, cmp=cmp_configs)))

Również nie używaj cmp, co jest deprecated. Użyj key i podaj mniej niż funkcję.

 3
Author: Mike Graham,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-15 17:59:57

" po prostu przeorganizuj mój kod, żebym nie miał tego problemu."Zgadza się. Łatwe do zrobienia. Zawsze działa.

Zawsze możesz podać funkcję przed jej odwołaniem.

"są jednak przypadki, kiedy jest to prawdopodobnie nieuniknione, na przykład przy implementacji niektórych form rekurencji"

Nie widzę, jak to możliwe. Proszę podać przykład miejsca, w którym nie można zdefiniować funkcji przed jej użyciem.

 1
Author: S.Lott,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-19 19:33:09

Chwileczkę. Kiedy twój moduł osiągnie instrukcję print w twoim przykładzie, zanim cmp_configs zostanie zdefiniowana, czego dokładnie oczekujesz?

Jeśli Twoje wysłanie pytania za pomocą print naprawdę próbuje przedstawić coś takiego:

fn = lambda mylist:"\n".join([str(bla)
                         for bla in sorted(mylist, cmp = cmp_configs)])

Wtedy nie ma wymogu zdefiniowania cmp_configs przed wykonaniem tej instrukcji, po prostu zdefiniuj ją później w kodzie i wszystko będzie dobrze.

Teraz, jeśli próbujesz odwołać się do cmp_configs jako wartości domyślnej z argumentu do lambda, to jest inna historia:

fn = lambda mylist,cmp_configs=cmp_configs : \
    "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)])

Teraz musisz zdefiniować cmp_configs zanim dotrzesz do tej linii.

[EDIT-ta następna część okazuje się niepoprawna, ponieważ domyślna wartość argumentu zostanie przypisana podczas kompilacji funkcji i ta wartość będzie używana nawet jeśli zmienisz wartość cmp_configs później.]

Na szczęście, Python jest tak przyjazny dla Typu, Jak to jest, nie obchodzi co zdefiniujesz jako cmp_configs, więc możesz poprzeć to stwierdzenie:

cmp_configs = None

I kompilator będzie szczęśliwy. Tylko pamiętaj, aby zadeklarować prawdziwe cmp_configs zanim kiedykolwiek wywołasz fn.

 0
Author: PaulMcG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-07 18:15:28

TL;DR: Python does not need forward declarations. Po prostu Umieść wywołania funkcji wewnątrz funkcji Def definicje , a wszystko będzie dobrze.

def foo(count):
    print("foo "+str(count))
    if(count>0):
        bar(count-1)

def bar(count):
    print("bar "+str(count))
    if(count>0):
        foo(count-1)

foo(3)
print("Finished.")

Funkcja rekurencyjna definicje , doskonale z powodzeniem daje:

foo 3
bar 2
foo 1
bar 0
Finished.

Jednak

bug(13)

def bug(count):
    print("bug never runs "+str(count))

print("Does not print this.")

Łamie na najwyższym poziomie wywołanie funkcji, która nie została jeszcze zdefiniowana i daje:

Traceback (most recent call last):
  File "./test1.py", line 1, in <module>
    bug(13)
NameError: name 'bug' is not defined

Python jest językiem interpretowanym, podobnie jak Lisp. Nie ma sprawdzania typu, tylko wywołania funkcji run-time, które kończą się sukcesem, jeśli nazwa funkcji została związana, a kończą się niepowodzeniem, jeśli jest niezwiązana.

Krytycznie, funkcja Def definicja nie wykonuje żadnego z funkcji wewnątrz swoich linii, po prostu deklaruje, z czego będzie składać się ciało funkcji. Znowu, to nawet nie sprawdza typu. Więc możemy to zrobić:

def uncalled():
    wild_eyed_undefined_function()
    print("I'm not invoked!")

print("Only run this one line.")

I działa doskonale (!), z wyjściem

Only run this one line.

Kluczem jest różnica między definicje i wywołania.

Interpreter wykonuje wszystko, co pojawia się na najwyższym poziomie, co oznacza, że próbuje go wywołać. Jeśli nie jest w definicji.
Twój kod wpada w kłopoty, ponieważ próbowałeś wywołać funkcję, na najwyższym poziomie w tym przypadku, zanim została powiązana.

Rozwiązaniem jest umieszczenie wywołania funkcji spoza najwyższego poziomu wewnątrz definicji funkcji, a następnie wywołanie tej funkcji kiedyś znacznie później.

Biznes o "if _ _ main _ _" jest idiomem opartym na tej zasadzie, ale musisz zrozumieć dlaczego, zamiast po prostu ślepo podążać za nią.

Z pewnością istnieją znacznie bardziej zaawansowane tematy dotyczące funkcji lambda i dynamicznego rebindingu nazw funkcji, ale to Nie to, o co prosił OP. Ponadto można je rozwiązać używając tych samych zasad: (1) defs define a function, they do not invocate their lines; (2) wpadasz w kłopoty, gdy wywołujesz symbol funkcji, który jest niezwiązany.

 0
Author: DragonLord,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-28 22:42:24

Python nie obsługuje deklaracji forward, ale powszechnym obejściem tego problemu jest użycie następującego warunku na końcu skryptu/kodu:

if __name__ == '__main__': main()

Z tym odczyta najpierw cały plik, a następnie oceni warunek i wywoła funkcję main (), która będzie w stanie wywołać dowolną zadeklarowaną funkcję forward, ponieważ wcześniej odczytała cały plik. Warunek ten wykorzystuje specjalną zmienną __name__, która zwraca wartość __main__ za każdym razem, gdy uruchamiamy Kod Pythona z bieżącego pliku (gdy kod był zaimportowany jako moduł, następnie __name__ zwraca nazwę modułu).

 0
Author: Mikhail,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-05 17:22:36

Jednym ze sposobów jest utworzenie funkcji obsługi. Zdefiniuj handler na początku i umieść handler pod wszystkimi metodami, które musisz wywołać.

Wtedy, gdy wywołasz metodę obsługi do wywołania funkcji, będą one zawsze dostępne.

Obsługa może przyjąć argument nameOfMethodToCall. Następnie używa kilku poleceń if do wywołania właściwej metody.

To rozwiąże twój problem.
def foo():
    print("foo")
    #take input
    nextAction=input('What would you like to do next?:')
    return nextAction

def bar():
    print("bar")
    nextAction=input('What would you like to do next?:')
    return nextAction

def handler(action):
    if(action=="foo"):
        nextAction = foo()
    elif(action=="bar"):
        nextAction = bar()
    else:
        print("You entered invalid input, defaulting to bar")
        nextAction = "bar"
    return nextAction

nextAction=input('What would you like to do next?:')

while 1:
    nextAction = handler(nextAction)
 -1
Author: obesechicken13,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-05 01:58:48

Tak, możemy to sprawdzić.

Input

print_lyrics() 
def print_lyrics():

    print("I'm a lumberjack, and I'm okay.")
    print("I sleep all night and I work all day.")

def repeat_lyrics():
    print_lyrics()
    print_lyrics()
repeat_lyrics()

Wyjście

I'm a lumberjack, and I'm okay.
I sleep all night and I work all day.
I'm a lumberjack, and I'm okay.
I sleep all night and I work all day.
I'm a lumberjack, and I'm okay.
I sleep all night and I work all day.

Jak wspomniał BJ Homer powyżej, ogólna zasada w Pythonie nie jest taka, że funkcja powinna być zdefiniowana wyżej w kodzie (jak w Pascalu), ale że powinna być zdefiniowana przed jej użyciem.

Mam nadzieję, że to pomoże.
 -4
Author: Satish Reddy Venkannagari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-08 04:41:10