2012-11-21 12 views
7

Istnieje lista: węzły = [20, 21, 22, 23, 24, 25].Jaka jest różnica między "()" i "[]" podczas generowania w Pythonie?

użyłem dwa sposoby, aby wygenerować nowe 2-Dimentional obiekty:

tour1 = (((a,b) for a in nodes)for b in nodes) 
tour2 = [[(a,b) for a in nodes ]for b in nodes] 

Rodzaj tour1 jest generator podczas tour2 jest lista:

In [34]: type(tour1) 
Out[34]: <type 'generator'> 

In [35]: type(tour2) 
Out[35]: <type 'list'> 

chcę wiem dlaczego tour1 nie jest krotką? Dzięki.

+6

Ponieważ jest to generator. Jakie jest Twoje pytanie? –

+3

@Daniel Część przed znakiem zapytania. Dlaczego nie krotka? – RickyA

Odpowiedz

10

Podstawową różnicą jest to, że pierwsza jest wyrażeniem generatora, a druga jest rozumieniem listy. Ten pierwszy daje tylko takie elementy, jakie są wymagane, podczas gdy drugi zawsze tworzy całą listę, gdy zrozumienie jest wykonywane.

Aby uzyskać więcej informacji, zobacz Generator Expressions vs. List Comprehension

Nie ma czegoś takiego jak „krotki pojmowania” w Pythonie, który jest to, czego zdają się oczekiwać od pierwszego składni.

Jeśli chcesz włączyć tour1 na krotką krotek, można użyć następujących:

In [89]: tour1 = tuple(tuple((a,b) for a in nodes)for b in nodes) 

In [90]: tour1 
Out[90]: 
(((20, 20), (21, 20), (22, 20), (23, 20), (24, 20), (25, 20)), 
((20, 21), (21, 21), (22, 21), (23, 21), (24, 21), (25, 21)), 
((20, 22), (21, 22), (22, 22), (23, 22), (24, 22), (25, 22)), 
((20, 23), (21, 23), (22, 23), (23, 23), (24, 23), (25, 23)), 
((20, 24), (21, 24), (22, 24), (23, 24), (24, 24), (25, 24)), 
((20, 25), (21, 25), (22, 25), (23, 25), (24, 25), (25, 25))) 
+0

Przeczytałem pytanie dotyczące wyrażenia generatora kontra rozumienie listy. Chcę się upewnić, że wyrażenie "lista (krotka ((a, b) dla węzła) dla b w węzłach)" jest bardziej wydajna niż "[[(a, b) dla węzłów] dla b w węzłach ] "? – zfz

10

Składnia dla krotki to nie nawiasy (), to przecinek ,. Można tworzyć krotki bez nawiasów:

x = 1, 2, 3 

Jeśli chcesz tworzyć krotki od A zrozumieniem, wystarczy użyć konstruktora tuple:

tuple(tuple((a,b) for a in nodes)for b in nodes) 
+0

Dzięki. Źle zrozumiałem użycie krotki. Następnie wygeneruj w ten sposób: tour1 = tuple ((((a, b) dla węzłów) dla b w węzłach). I tour1 to krotka! – zfz

2

To generator, ale można po prostu zmienić go na krotki :

>>> (i for i in xrange(4)) 
<generator object <genexpr> at 0x23ea9b0> 
>>> tuple(i for i in xrange(4)) 
(0, 1, 2, 3) 
2

Aby dodać ... Właściwie wyrażenie generator nie potrzebuje w ogóle nawiasów. Potrzebujesz ich tylko wtedy, gdy wyrażenie generator generuje złą składnię - tutaj z powodu przypisania. Podczas przekazywania generatora do funkcji (lub podobnego), nie potrzebujesz nawiasów. Wypróbuj następujące:

tour3 = list(list((a,b) for a in nodes) for b in nodes) 

Daje dokładnie taki sam wynik, jak Twój tour2. W ten sposób możesz spojrzeć na [ jak na cukier syntaktyczny dla list(, a ] to cukier syntaktyczny powiązany z ). Jednak kompilator kompiluje go inaczej. Można spróbować demontażu (trzeba przekazać funkcję):

>>> import dis 
>>> def fn1(): 
... return list(list((a,b) for a in nodes) for b in nodes) 
... 
>>> def fn2(): 
... return [[(a,b) for a in nodes ]for b in nodes] 
... 
>>> dis.dis(fn1) 
    2   0 LOAD_GLOBAL    0 (list) 
       3 LOAD_CONST    1 (<code object <genexpr> at 000000000229A9B0, file "<stdin>", line 2>) 
       6 MAKE_FUNCTION   0 
       9 LOAD_GLOBAL    1 (nodes) 
      12 GET_ITER 
      13 CALL_FUNCTION   1 
      16 CALL_FUNCTION   1 
      19 RETURN_VALUE 
>>> dis.dis(fn2) 
    2   0 BUILD_LIST    0 
       3 LOAD_GLOBAL    0 (nodes) 
       6 GET_ITER 
     >> 7 FOR_ITER    37 (to 47) 
      10 STORE_FAST    0 (b) 
      13 BUILD_LIST    0 
      16 LOAD_GLOBAL    0 (nodes) 
      19 GET_ITER 
     >> 20 FOR_ITER    18 (to 41) 
      23 STORE_FAST    1 (a) 
      26 LOAD_FAST    1 (a) 
      29 LOAD_FAST    0 (b) 
      32 BUILD_TUPLE    2 
      35 LIST_APPEND    2 
      38 JUMP_ABSOLUTE   20 
     >> 41 LIST_APPEND    2 
      44 JUMP_ABSOLUTE   7 
     >> 47 RETURN_VALUE 

Więc widać jest inaczej (tzn wygląda jak cukier składniowej, ale to nie jest).Niestety, Python nie wie, jak do demontażu generatora:

>>> g = (list((a,b) for a in nodes) for b in nodes) 
>>> dis.dis(g) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "C:\Python27\lib\dis.py", line 49, in dis 
type(x).__name__ 
TypeError: don't know how to disassemble generator objects 

Aktualizacja:

One mogą ulec pokusie - patrząc na powyższym zdemontowanego kodu - że fn1 jest szybszy (posiadające krótszy kod). Jednak w przypadku wszystkich wywołań funkcji we wszystkich językach wywołanie funkcji wygląda na krótszy niż rozwinięty kod. Nie mówi nic o wewnętrznych kodach. Niektóre punkty Zen Pythona:

>>> import this 
The Zen of Python, by Tim Peters 
... 
Readability counts. 
... 
In the face of ambiguity, refuse the temptation to guess. 
There should be one-- and preferably only one --obvious way to do it. 
... 
>>> 

Istnieje timeit standardowy moduł do pomiaru czasu wykonania. Spróbujmy wykorzystać go w dwóch przypadkach:

>>> import timeit 
>>> t = timeit.Timer('list(list((a,b) for a in nodes) for b in nodes)', 
...     'nodes = [20, 21, 22, 23, 24, 25]') 
>>> print("%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)) 
17.74 usec/pass 

a teraz z nawiasami kwadratowymi:

>>> t = timeit.Timer('[[(a,b) for a in nodes ]for b in nodes]', 
...     'nodes = [20, 21, 22, 23, 24, 25]') 
>>> print("%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)) 
7.14 usec/pass 
>>> 

To wyraźnie pokazuje, że uczynienie listy list poprzez [ ] jest szybsze. Powodem jest to, że jest mniej wywołań funkcji. Kompilator Pythona może produkować prostszy kod.

+0

Dzięki. Nie znam modułu "dis". Sądzę więc, że "fn1" jest bardziej efektywny niż "fn2"? – zfz

+0

@zfz: Nie. Pokazuje tylko, że kod jest inny. W rzeczywistości kod 'fn1' jest tylko otoką, aby wywołać funkcję generatora i uzyskać z niego wynik. 'Fn2' jest bardziej liniowy, bardziej bezpośredni. Zamierzam zaktualizować moją odpowiedź. – pepr

Powiązane problemy