2009-11-04 12 views
68

gram około z listowych i natknąłem się na ten mały urywek na innym miejscu:Czego backticks znaczy interpreter Pythona: `num`

return ''.join([`num` for num in xrange(loop_count)]) 

Spędziłem kilka minut próbuje replikować Funkcja (przez wpisanie) przed wykonaniem bitu `num` go zrywała.

Co robi załączanie instrukcji w tych znakach? Z tego, co widzę, jest to odpowiednik str (num). Ale kiedy planowane go:

return ''.join([str(num) for num in xrange(10000000)]) 

Zajmuje 4.09s natomiast:

return ''.join([`num` for num in xrange(10000000)]) 

trwa 2.43s.

Obie dają identyczne wyniki, ale jedna jest wolniejsza. Co tu się dzieje?

EDYCJA: Dziwnie ... repr() daje nieco wolniejsze wyniki niż `num`. 2,99 s vs 2,43 s. Korzystanie z Pythona 2.6 (jeszcze nie próbowałem wersji 3.0).

+8

Po przeczytaniu "innej strony" na http://skymind.com/~ocrow/python_string/, miałem podobne pytanie i znalazłem tę stronę. Ładne pytanie i miła odpowiedź :) – netvope

Odpowiedz

103

Cofamy są przestarzałym aliasem dla repr(). Nie używaj ich więcej, składnia została usunięta w Pythonie 3.0.

Korzystanie z przycisków odsyłania wydaje się szybsze niż używanie repr(num) lub num.__repr__() w wersji 2.x. Sądzę, że dzieje się tak, ponieważ dodatkowe wyszukiwanie słownika jest wymagane w globalnej przestrzeni nazw (dla repr) lub w przestrzeni nazw obiektu (dla __repr__).


Korzystanie z modułu dis potwierdza moje przypuszczenie:

def f1(a): 
    return repr(a) 

def f2(a): 
    return a.__repr__() 

def f3(a): 
    return `a` 

demontażu Wystawy:

>>> import dis 
>>> dis.dis(f1) 
    3   0 LOAD_GLOBAL    0 (repr) 
       3 LOAD_FAST    0 (a) 
       6 CALL_FUNCTION   1 
       9 RETURN_VALUE 
>>> dis.dis(f2) 
    6   0 LOAD_FAST    0 (a) 
       3 LOAD_ATTR    0 (__repr__) 
       6 CALL_FUNCTION   0 
       9 RETURN_VALUE   
>>> dis.dis(f3) 
    9   0 LOAD_FAST    0 (a) 
       3 UNARY_CONVERT  
       4 RETURN_VALUE 

f1 obejmuje globalne wyszukiwanie dla repr, f2 odnośnika atrybutu dla __repr__, natomiast lewy apostrof Operator jest zaimplementowany w oddzielnym kodzie operacji. Ponieważ nie ma żadnego narzutu dla wyszukiwania słownika (LOAD_GLOBAL/LOAD_ATTR), ani dla wywołań funkcji (CALL_FUNCTION), backticks są szybsze.

myślę, że ludzie Python zdecydował, że posiadanie oddzielnej operacji niskiego poziomu dla repr() nie warto, i posiadające obie repr() i odwrócone, pojedyncze apostrofy narusza zasadę

„Nie powinno być jedno-, a korzystnie tylko jeden - czysty sposób na zrobienie tego "

, więc funkcja została usunięta w Pythonie 3.0.

+0

Zobacz moją ostatnią edycję na repr() –

+0

Chciałem znaleźć, jak można zastąpić backticks z niektórych funkcji, ale wydaje się, że nie jest to możliwe, czy jest to? – Jiri

+2

Użyj repr() zamiast backticks. Backticks to amortyzowana składnia dla repr() come 3.0. Właściwie wolę wygląd backticksów niż wywoływanie funkcji ANOTHER. –

1

Domyślam się, że num nie definiuje metody __str__(), więc str() musi wykonać drugie wyszukiwanie dla __repr__.

Cofa się bezpośrednio pod numer __repr__. Jeśli jest to prawdą, użycie opcji repr() zamiast przycisków tylnych powinno dać takie same wyniki.

9

grawis powołując się na ogół bez użyteczny i poszedł w Pythonie 3.

Na co warto, to:

''.join(map(repr, xrange(10000000))) 

jest nieznacznie szybciej niż w wersji grawis dla mnie. Ale martwienie się tym jest prawdopodobnie przedwczesną optymalizacją.

+2

Dlaczego cofnąć się o krok i użyć mapy zamiast pojmowania list/iteratora? – nikow

+3

Właściwie, 'timeit' daje szybsze rezultaty dla'. '(Odwzorowanie (repr, xrange (0, 1000000))) niż dla '' '.join ([repr (i) dla i w xrange (0, 1000000)]) '(jeszcze gorzej dla' '' .join ((repr (i) dla i w xrange (0, 1000000))) '). To trochę rozczarowujące ;-) – RedGlyph

+5

Wynik bobince'a nie jest dla mnie zaskakujący. Zgodnie z regułą, niejawne pętle w Pythonie są szybsze niż jawne, często dramatycznie szybsze. 'map' jest zaimplementowane w C przy użyciu pętli C, która jest znacznie szybsza niż pętla Pythona wykonana na maszynie wirtualnej. –