2017-09-14 24 views
7

w tym kodzie:Dlaczego różne nazwy zmiennych mają różne wyniki (python2.7)?

results = [] 
for i in [1, 2, 3, 4]: 
    def inner(y): 
     return i 
    results.append(inner) 

for i in results: 
    print i(None) 

wyjście jest "funkcja wewnętrzna w 0x107dea668"

gdybym zmienić í do drugiej litery, na przykład:

results = [] 
for i in [1, 2, 3, 4]: 
    def inner(y): 
     return i 
    results.append(inner) 

for j in results: 
    print j(None) 

wyjście to "4"


odpowiedzi

results = [] 
for i in [1, 2, 3, 4]: 
    def inner(y): 
     print "in inner:%s " % id(i) 
     return i 
    results.append(inner) 

# i -> 4 
for i in results: 
    # i -> func inner 
    print "i: %s" % i 
    print "in loop: %s " % id(i) 

    # func inner <===> A 
    # i == A -> return i -> return A, so when call funtion inner, will return itself 
    # print "call: %s" % i(None) 

    print "call: %s" % i(None)(None)(None) 
    print "------------------------------" 

I: funkcją wewnętrzną w 0x101344d70
w pętli: 4315172208
w wewnętrzny: 4315172208
w wewnętrzny: 4315172208
w wewnętrznej: 4315172208
połączenia: funkcja wewnętrzna w 0x101344d70

I: funkcją wewnętrzną w 0x101344de8
w pętli: 4315172328
w wewnętrzny: 4315172328
w wewnętrzny: 4315172328
w wewnętrzny: 4315172328
połączenie: funkcją wewnętrzną w 0x101344de8

I: w funkcji wewnętrznej w 0x101344e60
w pętli: 4315172448
w wewnętrzny: 4315172448
w wewnętrzny: 4315172448
w wewnętrzny: 4315172448
połączenie: funkcją wewnętrzną w 0x101344e60

I: funkcją wewnętrzną w 0x101344ed8
w pętli: 4315172568
w wewnętrzny: 4315172568
w wewnętrzny: 4315172568
w wewnętrzny: 4315172568
połączenie: funkcją wewnętrzną w 0x101344ed8

+3

po prostu spotkał leniwe ocenę 'I' –

+0

związane: https://stackoverflow.com/questions/42805800/generator-comprehension-different-output-from-list-comprehension –

+0

To nie jest powiązany do leniwej oceny, jest to kwestia kontekstowa. Leniwa ocena polega na ocenie w razie potrzeby, a nie gdzie. –

Odpowiedz

1

zmiennej i zwrócone funkcja inner zachowuje wartość z ostatniego kontekstu, w którym została przypisana.

Jeśli debugujesz kod, używając punktu przerwania wewnątrz funkcji inner, obraz stanie się jaśniejszy, jeśli wybierzesz poprzednią klatkę/kontekst (lewy dolny rycinowy rysunek) przed wywołaniem funkcji.

Gdy używasz i, jest on przypisany wewnątrz drugiego for, więc będzie miał funkcję jako jego wartość (podświetloną na żółto na rysunku 1).

Figure 1

Teraz, jeśli używasz j, zmienna i zachowa swoją ostatnią wartość z poprzedniego związku: the for na liście (Rys 2).

Figure 2

1

W rzeczywistości, gdy używasz j w wynikach, zmienną i pozostaje 4, z powodu po pierwszej pętli, i pozostaje liczbą 4;

Ale jeśli użyjesz i w wynikach, odwołuję się do funkcji zapisanych w wynikach. I nie jest naprawiony, dopóki nie zaczniesz go wywoływać. jak powiedział @ Jean-François Fabre, leniwa ocena.

Dodatkowo jeśli chce wewnętrzną funkcję przechowywania każdego i gdy pętla jest spośród 1-4, należy przechowywać I w związanej zakresie użyć częściowe funkcji;

from functools import partial 

results = [] 
for i in [1, 2, 3, 4]: 
    def inner(i, y): 
     return i 


    results.append(partial(inner, i)) 

for i in results: 
    print(i(None)) 

to daje rezultaty

1 
2 
3 
4 

który jest bardziej sensowne.

3

Zdefiniowana funkcja inner zawiera wolną zmienną odnoszącą się do zmiennej globalnej i. Jest to chyba jaśniej przykład tak:

def inner(y): 
    return i 

i = 1 
print inner(None) 

i = 2 
print inner(None) 

która drukuje 1, a następnie 2

w pierwszym przykładzie, w momencie powołania do inner, i ma wartość, która jest funkcją i więc to jest drukowane, gdy wywoływana jest i (która jest inner).

W drugim przykładzie, w momencie powołania do inner, i ma wartość 4, a więc to, co jest drukowane przy j (co jest inner) jest tzw.

Wyraźnym sposobem na wyrażenie tego, co prawdopodobnie chciałeś tutaj, jest użycie funkcji częściowo oce- nianej, zgodnie z zaleceniami w innym answer. Innym sposobem jest użycie funkcji zamykającej w celu utworzenia zamknięcia. W ten sposób:

results = [] 
for i in [1, 2, 3, 4]: 
    def outer(k): 
     def inner(y): 
      return k 
     return inner 
    results.append(outer(i)) 

for i in results: 
    print i(None) 

, który wydrukuje od 1 do 4, jak prawdopodobnie chcesz.

mały trick czasami stosowane w Pythonie jest stosowanie wartości domyślnych zmiennej jako komórka zawiera wartość:

results = [] 
for i in [1, 2, 3, 4]: 
    def inner(y, i = i): 
     return i 
    results.append(inner) 

for i in results: 
    print i(None) 

drukowany również od 1 do 4.