Bawię się ze zrozumieniem list i natknąłem się na ten mały fragment na innej stronie:
return ''.join([`num` for num in xrange(loop_count)])
Spędziłem kilka minut próbując odtworzyć funkcję (wpisując), zanim zdałem sobie sprawę, że `num`
bit ją psuje.
Co robi umieszczenie oświadczenia w tych znakach? Z tego, co widzę, jest to odpowiednik str (num). Ale kiedy to ustaliłem:
return ''.join([str(num) for num in xrange(10000000)])
Zajmuje to 4,09s natomiast:
return ''.join([`num` for num in xrange(10000000)])
trwa 2,43s.
Oba dają identyczne wyniki, ale jeden jest znacznie wolniejszy. Co tu się dzieje?
EDYCJA: Dziwne ... repr()
daje nieco wolniejsze wyniki niż `num`
. 2,99s vs 2,43s. Używanie Pythona 2.6 (jeszcze nie wypróbowałem 3.0).
python
list-comprehension
Dominic Bou-Samra
źródło
źródło
Odpowiedzi:
Backticks to przestarzały alias dla
repr()
. Nie używaj ich więcej, składnia została usunięta w Pythonie 3.0.Wydaje się, że używanie grawitacji jest szybsze niż używanie
repr(num)
lubnum.__repr__()
w wersji 2.x. Wydaje mi się, że dzieje się tak dlatego, że dodatkowe wyszukiwanie w słowniku jest wymagane odpowiednio w globalnej przestrzeni nazw (dlarepr
) lub w przestrzeni nazw obiektu (dla__repr__
).Korzystanie z
dis
modułu potwierdza moje przypuszczenie:def f1(a): return repr(a) def f2(a): return a.__repr__() def f3(a): return `a`
Demontaż programów:
>>> 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 wyszukiwanierepr
,f2
wyszukiwanie atrybutów__repr__
, podczas gdy operator cofania jest zaimplementowany w oddzielnym kodzie operacyjnym. Ponieważ nie ma narzutu na przeszukiwanie słownika (LOAD_GLOBAL
/LOAD_ATTR
) ani na wywołania funkcji (CALL_FUNCTION
), grawerowanie jest szybsze.Wydaje mi się, że ludzie z Pythona zdecydowali, że posiadanie oddzielnej operacji niskiego poziomu
repr()
nie jest tego warte, a posiadanie oburepr()
i lewych apostrofów narusza zasadęwięc funkcja została usunięta w Pythonie 3.0.
źródło
Cytowanie Backtick jest generalnie nieprzydatne i zniknęło w Pythonie 3.
Cóż to jest warte:
''.join(map(repr, xrange(10000000)))
jest dla mnie nieznacznie szybszy niż wersja backtick. Ale martwienie się tym jest prawdopodobnie przedwczesną optymalizacją.
źródło
timeit
daje szybsze wyniki dla''.join(map(repr, xrange(0, 1000000)))
niż dla''.join([repr(i) for i in xrange(0, 1000000)])
(nawet gorzej dla''.join( (repr(i) for i in xrange(0, 1000000)) )
). To trochę rozczarowujące ;-)map
jest zaimplementowany w C, przy użyciu pętli C, która jest znacznie szybsza niż pętla Pythona wykonywana na maszynie wirtualnej.map
wydaje mi się całkowicie jasny i zwięzły, a nawet nie znam Pythona.Domyślam się, że
num
nie definiuje metody__str__()
, więcstr()
trzeba przeprowadzić drugie wyszukiwanie__repr__
.Backticks szukają bezpośrednio
__repr__
. Jeśli to prawda, użycierepr()
zamiast grawisów powinno dać takie same wyniki.źródło