2012-01-29 13 views
5

w Pythonie, często ponowne zmienne w sposób analogiczny do tego:Ponowne użycie zmiennych w Pythonie

files = files[:batch_size] 

Lubię tę technikę, ponieważ pomaga mi wyciąć od liczby zmiennych muszę śledzić.

Nigdy nie miałem żadnych problemów, ale zastanawiam się, czy brakuje mi potencjalnych wad, np. wydajność itp

+0

Nie widzę tutaj pytania. Jaka jest alternatywa do porównania? Używanie drugiej zmiennej, takiej jak 'files = XYZ; files_head = files [: batch_size] '? Dlaczego miałaby być jakaś różnica? –

+0

alternatywa jest czymś w rodzaju: new_set_of_files = files [: batch_size] – jldupont

+0

Od razu zauważysz główną: * Hej! Nadal potrzebuję tej starej wartości dla 'files'! *. – Droogans

Odpowiedz

6

Nie ma technicznych wad dla ponownego użycia nazw zmiennych. Jeśli jednak ponownie użyjesz zmiennej i zmienisz jej "cel", może to zmylić innych czytających Twój kod (szczególnie, jeśli przegapią zmianę przypisania).

W podanym przykładzie zdajesz sobie sprawę, że w rzeczywistości tworzysz całkiem nową listę, gdy się splisujesz. Dopóki GC nie zbierze starej kopii tej listy, ta lista zostanie zapisana w pamięci dwukrotnie (z wyjątkiem tego, co zostało spliced ​​out). Alternatywą jest iteracja na tej liście i zatrzymanie się po osiągnięciu elementu batch_size, zamiast kończenia listy, a nawet bardziej zwięzłej, del files[batch_size:].

+0

+1 Przyjemny punkt o tym, jak można uniknąć tworzenia nowego obiektu (choć być może jest on mniej czytelny?) – RoundTower

+1

@cheeken: Jeszcze inna alternatywa (prawdopodobnie najbardziej Pythonic) to stworzenie generatora z 'itertools.islice'. –

+0

Dobre połączenie, @NiklasBaumstark! Tym, którzy odrzucili: Byłbym wdzięczny za komentarz wyjaśniający, dlaczego tak mógłbym to poprawić. – cheeken

5

Kilka informacji o tym konkretnym przykładzie: Jeśli chcesz tylko do iteracji, map lub filtrować wyniki, można użyć generatora, aby uniknąć kopię tablicy:

import itertools 
files = itertools.islice(files, batch_size) 

chodzi o ogólnym przypadku : Niezależnie od tego, czy przypisujesz nową wartość do istniejącej już nazwy, czy do nowej, nie ma absolutnie żadnej różnicy (przynajmniej z punktu widzenia interpretera/maszyny wirtualnej). Obie metody produkować niemal dokładnie ten sam kod bajtowy:

Python 2.7.2 (default, Nov 21 2011, 17:25:27) 
[GCC 4.6.2] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import dis 
>>> def func1(files): 
... files = files[:100] 
... 
>>> def func2(files): 
... new_files = files[:100] 
... 
>>> dis.dis(func1) 
    2   0 LOAD_FAST    0 (files) 
       3 LOAD_CONST    1 (100) 
       6 SLICE+2    
       7 STORE_FAST    0 (files) 
      10 LOAD_CONST    0 (None) 
      13 RETURN_VALUE   
>>> dis.dis(func2) 
    2   0 LOAD_FAST    0 (files) 
       3 LOAD_CONST    1 (100) 
       6 SLICE+2    
       7 STORE_FAST    1 (new_files) 
      10 LOAD_CONST    0 (None) 
      13 RETURN_VALUE   

To samo można zaobserwować w Pythonie 3.

W rzeczywistości func1 może być nawet nieco szybciej, ponieważ nazwa files został widział i mógł już znajduje się w pamięci podręcznej zmiennych.

+0

Czy mogę cię zapytać, jaka różnica sprawi, że ten inny "1"? –

+0

@Rik: Myślę, że jest to indeks zmiennej lokalnej, której dotyczy problem ("0" w pierwszym przypadku, ponieważ jest to pierwsza dostępna zmienna, '1' w drugim przypadku). Nie jestem jednak w 100% pewny. –

1

Naprawdę nie ma wielu wad, aby ponownie wykorzystać zmienne, oprócz tego, że nie doświadczasz też wielu zalet. Python GC i tak będzie musiał zostać uruchomiony, aby zebrać stary obiekt, więc nie ma natychmiastowego przyrostu pamięci, gdy nadpisujesz zmienną, w przeciwieństwie do języków skompilowanych statycznie, takich jak C, gdzie ponowne użycie zmiennej uniemożliwia całkowicie przydzielanie pamięci dla nowy obiekt.

Co więcej, można naprawdę pomylić wszystkich przyszłych czytelników kodu, którzy generalnie oczekują, że nowe obiekty będą miały nowe nazwy (produkt uboczny zbieranych śmieci).

1

Minusem byłoby, że nie można używać:

file_rest = files[batch_size:] 

Odnośnie wydajności nie jest minusem. Wręcz przeciwnie: możesz nawet poprawić wydajność, unikając kolizji mieszania w tej samej przestrzeni nazw.

W tym kontekście było SO-post.