Jakie korzyści lub konsekwencje moglibyśmy uzyskać dzięki kodowi Python w ten sposób:
class some_class(parent_class):
def doOp(self, x, y):
def add(x, y):
return x + y
return add(x, y)
Znalazłem to w projekcie open source, robiąc coś pożytecznego wewnątrz zagnieżdżonej funkcji, ale nie robiąc absolutnie nic poza nią, z wyjątkiem wywoływania jej. (Właściwy kod można znaleźć tutaj .) Dlaczego ktoś mógłby zakodować to w ten sposób? Czy istnieje jakaś korzyść lub efekt uboczny pisania kodu wewnątrz funkcji zagnieżdżonej, a nie w zewnętrznej, normalnej funkcji?
python
nested-function
Hosam Aly
źródło
źródło
Odpowiedzi:
Zwykle robisz to, aby zamknąć :
def make_adder(x): def add(y): return x + y return add plus5 = make_adder(5) print(plus5(12)) # prints 17
Funkcje wewnętrzne mogą uzyskiwać dostęp do zmiennych z otaczającego zakresu (w tym przypadku zmiennej lokalnej
x
). Jeśli nie uzyskujesz dostępu do żadnych zmiennych z otaczającego zakresu, w rzeczywistości są to zwykłe funkcje z innym zakresem.źródło
plus5 = functools.partial(operator.add, 5)
. Dekoratory byłyby lepszym przykładem zamknięć.Oprócz generatorów funkcji, gdzie tworzenie funkcji wewnętrznych jest prawie definicją generatora funkcji, powodem tworzenia funkcji zagnieżdżonych jest poprawa czytelności. Jeśli mam małą funkcję, która będzie wywoływana tylko przez funkcję zewnętrzną, wstawiam definicję, abyś nie musiał przeskakiwać, aby określić, co robi ta funkcja. Zawsze mogę przenieść wewnętrzną metodę poza metodę hermetyzacji, jeśli stwierdzę potrzebę ponownego użycia funkcji w późniejszym terminie.
Przykład zabawki:
import sys def Foo(): def e(s): sys.stderr.write('ERROR: ') sys.stderr.write(s) sys.stderr.write('\n') e('I regret to inform you') e('that a shameful thing has happened.') e('Thus, I must issue this desultory message') e('across numerous lines.') Foo()
źródło
Jedną z potencjalnych zalet używania metod wewnętrznych jest to, że umożliwia użycie zmiennych lokalnych metody zewnętrznej bez przekazywania ich jako argumentów.
def helper(feature, resultBuffer): resultBuffer.print(feature) resultBuffer.printLine() resultBuffer.flush() def save(item, resultBuffer): helper(item.description, resultBuffer) helper(item.size, resultBuffer) helper(item.type, resultBuffer)
można zapisać w następujący sposób, co prawdopodobnie brzmi lepiej
def save(item, resultBuffer): def helper(feature): resultBuffer.print(feature) resultBuffer.printLine() resultBuffer.flush() helper(item.description) helper(item.size) helper(item.type)
źródło
Nie potrafię sobie wyobrazić żadnego dobrego powodu dla takiego kodu.
Może był powód dla wewnętrznej funkcji w starszych wersjach, podobnie jak w innych Ops.
Na przykład ma to nieco większy sens:
class some_class(parent_class): def doOp(self, op, x, y): def add(x, y): return x + y def sub(x,y): return x - y return locals()[op](x,y) some_class().doOp('add', 1,2)
ale wtedy funkcja wewnętrzna powinna być („prywatną”) metodą klasową:
class some_class(object): def _add(self, x, y): return x + y def doOp(self, x, y): return self._add(x,y)
źródło
Idea metod lokalnych jest podobna do zmiennych lokalnych: nie zanieczyszczaj większej przestrzeni nazw. Oczywiście korzyści są ograniczone, ponieważ większość języków nie zapewnia również bezpośrednio takiej funkcjonalności.
źródło
Czy na pewno kod był dokładnie taki? Normalnym powodem zrobienia czegoś takiego jest utworzenie częściowej - funkcji z wprowadzonymi parametrami. Wywołanie funkcji zewnętrznej zwraca wywołanie, które nie wymaga parametrów, dlatego może być przechowywane i używane gdzieś, niemożliwe jest przekazanie parametrów. Jednak wysłany kod tego nie zrobi - wywołuje funkcję natychmiast i zwraca wynik, a nie wywoływalny. Przydatne może być opublikowanie rzeczywistego kodu, który widziałeś.
źródło