2013-06-10 12 views
5

Nie mam na myśli zamknięć, gdzie funkcja zewnętrzna zwraca wewnętrzną funkcję, lub w szczególności do zapamiętywania. Było kilka przypadków, w których chciałem napisać funkcję rekursywną, być może z pamięcią, i wydawało się o wiele łatwiejsze zainicjowanie aa dyktatury lub jakiejś innej struktury danych w zewnętrznej funkcji, a następnie mieć rekursywną funkcję pomocniczą zapisującą i dostęp do dyktatu i argumentów funkcji zewnętrznej. Oto co mam na myśli -Kiedy dobrze jest korzystać z funkcji zagnieżdżonych w Pythonie?

def foo(arr, l): 
    cache = {} 
    result = [] 

    def recursive_foo_helper(i, j, k): 
     # some code that depends on arr, l, i, j, k, cache, and result 

    for (x, y) in arr: 
     if recursive_foo_helper(x, y, k): 
     return result 
    return None 

zamiast posiadające funkcję pomocnika zgłaszać osobno z jakimś bardzo długim podpisania podobnego

recursive_foo_helper(arr, l, i, j, k, cache={}, result=[]) 

Czytałem, że ten sposób jest dość standardowy dla memoization, ale byłem ciekawy, czy istnieje konsensus co do tego, czy można to zrobić tylko dla rekurencyjnych funkcji pomocnika.

+0

Jeśli nie wywołasz tej funkcji w innych miejscach, nie widzę powodu, dla którego byłoby to złe. – OptimusCrime

Odpowiedz

4

używać zagnieżdżonych funkcji znaleźć mecze z listy:

def get_exact(data, key, match): 
    def is_match(item): 
     if (key in item) and (item[key].lower() == match.lower()): 
      return item 
     return False 
    return [i for i in data if is_match(i)] 

Brak innych połączeń w projekcie mają potrzebę skorzystania is_match (pozycja), dlaczego więc uznać je oddzielnie?

Jednakże, powiem, że na mój przykład deklarowanie is_match() poza get_exact() działa szybciej w 10.000 iteracjach wokół ~0.04 seconds.

def is_match(item, key, match): 
    if (key in item) and (item[key].lower() == match.lower()): 
     return item 
    return False 

def get_exact(data, key, match): 
    return [i for i in data if is_match(i, key, match)] 
1

Powiedziałbym, stosując zamknięcie jak sugerujesz jest czystsze, ale naprawdę potrzebuje nonlocal kluczowe z Python3 jeśli chcesz ponownie powiązać referencje. W przypadku obiektów zmiennych możliwe jest ich modyfikowanie.

W międzyczasie, to jest powszechne, aby zobaczyć hacki defaultarg/idiomy w python2

One (być może jedyną) Wadą funkcji zagnieżdżonych jest to, że trudno unittest.

Aby upewnić się, że pamięć podręczna nie może rozwijać się bez granic, trzeba również sposób usunąć elementy (np najdawniej używane)

1

Istnieje wiele dobrych powodów. Osobiście często używam zagnieżdżonych funkcji, aby zachować przestrzeń nazw. Jest to szczególnie przydatne w zasięgu metod obiektowych:

class Foo(object): 
    def bar(self): 
     def baz(val): 
      return val 
     return [ baz(i) for i in range(1,101) ] 

Jeśli oświadczam baz poza bar, to albo trzeba zrobić to metoda Foo lub narazić go do całego pakietu.

2

Zazwyczaj używam zamknięć, jednak w inny sposób sugerujesz (co czasami nazywam Wrapper) jest również bardzo przydatny i na podstawie mojego osobistego doświadczenia działa dobrze. Nigdy nie kazałem komuś mówić, żebym unikał tego stylu. Jeśli twój kod działa i jest czytelny (co moim zdaniem jest), to idź do niego!

Powiązane problemy