Co oznaczają znaki odwrotne dla interpretera Pythona: „num”


88

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).


8
Po przeczytaniu „innej witryny” pod adresem skymind.com/~ocrow/python_string , miałem podobne pytanie i znalazłem tę stronę. Ładne pytanie i miła odpowiedź :)
netvope

Odpowiedzi:


123

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)lub num.__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 (dla repr) lub w przestrzeni nazw obiektu (dla __repr__).


Korzystanie z dismoduł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   

f1obejmuje globalne wyszukiwanie repr, f2wyszukiwanie 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 obu repr()i lewych apostrofów narusza zasadę

„Powinien być jeden - a najlepiej tylko jeden - oczywisty sposób na zrobienie tego”

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


Chciałem dowiedzieć się, jak można zamienić znaki odwrotne na jakieś wywołanie funkcji, ale wygląda na to, że nie jest to możliwe, czy tak jest?
Jiri

2
Użyj repr () zamiast znaków odwrotnych. Backticks to przestarzała składnia repr () w wersji 3.0. Właściwie wolę wygląd klawiszy odwrotnych niż wywoływanie INNEJ funkcji.
Dominic Bou-Samra

8
Powodem wycofywania znaków odwrotnych jest również sam znak; może być trudno pisać (na niektórych klawiaturach), trudno zobaczyć, co to jest, trudno poprawnie wydrukować w książkach Pythona. Itd.
u0b34a0f6ae

4
@ kaizer.se: Dziękuję za zwrócenie uwagi. Jest to prawdopodobnie główny powód porzucania znaków odwrotnych, patrz oświadczenie Guidos w archiwach list dyskusyjnych: mail.python.org/pipermail/python-ideas/2007-J January
Ferdinand Beyer

Pierwotne pytanie, które zostało wysłane, brzmiało, ponieważ nie mogłem znaleźć klawiszy odwrotnych na mojej klawiaturze;) Poniżej tyldy wydaje się, że po googlowaniu.
Dominic Bou-Samra

10

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ą.


2
Po co cofać się o krok i używać map zamiast list / iteratorów?
ników

4
W rzeczywistości timeitdaje 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 ;-)
RedGlyph

8
Wynik bobince'a nie jest dla mnie zaskoczeniem. Zasadniczo niejawne pętle w Pythonie są szybsze niż jawne, często znacznie szybsze. mapjest zaimplementowany w C, przy użyciu pętli C, która jest znacznie szybsza niż pętla Pythona wykonywana na maszynie wirtualnej.
Ferdinand Beyer

7
Nie jest to również zaskoczeniem, jest to po prostu szkoda dla reputacji list złożonych (z wynikiem 30% w tym przykładzie). Ale wolałbym mieć jasny niż błyskawiczny kod, chyba że jest to naprawdę ważne, więc nie ma tu nic wielkiego. Biorąc to pod uwagę, funkcja map () nie wydaje mi się niejasna, LC są czasami przereklamowane.
RedGlyph

4
mapwydaje mi się całkowicie jasny i zwięzły, a nawet nie znam Pythona.
Zenexer

1

Domyślam się, że numnie definiuje metody __str__(), więc str()trzeba przeprowadzić drugie wyszukiwanie __repr__.

Backticks szukają bezpośrednio __repr__. Jeśli to prawda, użycie repr()zamiast grawisów powinno dać takie same wyniki.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.