Jeżeli sprawozdanie funkcyjne są wykonywane są one zobowiązane do ich zakresu (leksykalnie) osłaniającego.
W Twoim ujęciu Lambda jest powiązana z zasięgiem globalnym, ponieważ pakiety for
nie są wykonywane w Pythonie jako jednostka o niezależnym zakresie. Na końcu pętli for
, num
jest związany w otaczającym zakresie. Demo:
for num in range(1, 6):
pass
assert num == 5 # num is now bound in the enclosing scope
Więc kiedy wiążą identyfikatory w pętli for
jesteś rzeczywiście manipulowania zakresu obejmującego.
for num in range(1, 6):
spam = 12
assert num == 5 # num is now bound in the enclosing scope
assert spam == 12 # spam is also bound in the enclosing scope
samą ofertę dla listowych:
[num for num in range(1, 6)]
assert num == 5
niewiarygodny, wiem. Anywho, dzięki naszej nowo poznanej wiedzy, możemy określić, że tworzone lambdy odnoszą się do (pojedynczego) identyfikatora związanego w otaczającym oscyloskopie. Które powinny uczynić to więcej sensu:
functions = []
for number in range(1, 6):
def fun():
return number
functions.append(fun)
assert all(fun() == 5 for fun in functions)
assert all(fun() is number for fun in functions)
A oto najfajniejsza część, która pokazuje, że nawet więcej:
# Same as above -- commented out for emphasis.
#functions = []
#for number in range(1, 6):
# def fun():
# return number
# functions.append(fun)
#assert all(fun() == 5 for fun in functions)
#assert all(fun() is number for fun in functions)
number = 6 # Rebind 6 in the scope and see how it affects the results.
assert all(fun() == 6 for fun in functions)
więc rozwiązanie to, oczywiście, jest, aby nowy zakres otaczającą dla każde number
, które chcesz powiązać. W Pythonie możesz tworzyć nowe obramowania z modułami, klasami i funkcjami. Często używa się funkcji tylko do utworzenia nowego zakresu obejmującego inną funkcję.
W języku Python zamknięcie jest funkcją, która powoduje, że zwraca inną funkcję. Coś jak konstruktor funkcji. Sprawdź get_fun
w poniższym przykładzie:
def get_fun(value):
""":return: A function that returns :param:`value`."""
def fun(): # Bound to get_fun's scope
return value
return fun
functions = []
for number in range(1, 6):
functions.append(get_fun(number))
assert [fun() for fun in functions] == range(1, 6)
Od get_fun
jest funkcją, to dostaje się mieć własną przestrzeń wewnętrzną. Za każdym razem, gdy wywołujesz get_fun
z wartością, tworzona jest mała tabela, aby śledzić powiązania w niej; tzn. mówi: "W tym zakresie identyfikator value
wskazuje na rzecz, która została przekazana." Zasięg ten kończy się po zakończeniu wykonywania funkcji, chyba że istnieje powód, żeby się kręcić.
Jeśli zwracasz funkcję z zakresu, jest to dobry powód, dla którego część tabeli zakresu może się kręcić - funkcja, którą powracasz, może odwoływać się do rzeczy z tej tabeli zakresu, gdy ją wywołasz. później. Z tego powodu, gdy fun
jest tworzony w ramach get_fun
, Python podaje fun
około tabelę zakresu, która fun
jest przydatna, gdy jest potrzebna.
Możesz przeczytać więcej o szczegółach i terminologii technicznej (która nieco złagodniałem) w Python docs on the execution model. Możesz także spojrzeć na części otaczającego zakresu, do których odnosi się funkcja z print fun.__closure__
. W powyższym przykładzie widzimy odniesienie do value
, co zdarza się być int:
# Same as before, commented out for emphasis.
#functions = []
#for number in range(1, 6):
# functions.append(get_fun(number))
#assert [fun() for fun in functions] == range(1, 6)
print functions[0].__closure__
# Produces: (<cell at 0x8dc30: int object at 0x1004188>,)
Cool. Czy to "hack" udokumentowane w dowolnym miejscu? Czy istnieje lepszy sposób na curry? Proszę również, nie wspominać o obrotowym łóżku. –
Nigdy nie widziałem tego wyraźnie wymienionego w żadnej dokumentacji. Wykorzystuje to fakt, że wartości domyślne dla parametrów funkcji są przypisywane w momencie tworzenia funkcji, co jest udokumentowane. – recursive
Ten przykład jest prawie taki sam jak [Dlaczego lambda zdefiniowana w pętli z różnymi wartościami zwraca ten sam wynik?] (Https://docs.python.org/3.4/faq/programming.html#why-do-lambdas- zdefiniowane w pętli-z-różnymi wartościami-all-return-the-same-result) z dokumentów. – abarnert