2014-09-05 12 views
6

Byłem zdezorientowany dzisiaj przez porównanie łańcuchowe: wydaje się, że Python ponownie używa ciągów (co jest sensowną rzeczą, ponieważ są one niezmienne). Aby sprawdzić ten fakt, zrobiłem co następuje:W jaki sposób Python robi ciąg magii?

>>> a = 'xxx' 
>>> b = 'xxx' 
>>> a == b 
True 
>>> a is b 
True 
>>> id(a) 
140141339783816 
>>> id(b) 
140141339783816 
>>> c = 'x' * 3 
>>> id(c) 
140141339783816 
>>> d = ''.join(['x', 'x', 'x']) 
>>> id(d) 
140141339704576 

Co jest nieco zaskakujące. kilka pytań:

  • Czy python sprawdza całą zawartość swojej tablicy łańcuchów podczas definiowania nowych ciągów?
  • Czy istnieje ograniczenie rozmiaru łańcucha?
  • Jak działa ten mechanizm (porównywanie skrótów łańcuchów?)
  • Nie wydaje się jednak, aby był używany dla wszystkich rodzajów generowanych ciągów. Jaka jest tu zasada?
+0

'is' testy tożsamość, czyli miejsc pamięci . '==' sprawdza równość. Nie jest rozsądnie używać ich zamiennie, ponieważ niektóre łańcuchy znaków, int itp. Są internowane w imię optymalizacji. – inspectorG4dget

+0

Dzięki, ale już to wiem (o nic nie pytałem). Moje pytanie nie dotyczy 'jest' kontra' == ': chodzi o to, w jaki sposób wewnętrznie pyton ponownie używa ciągów. Innymi słowy, o wewnętrznej implementacji używanej przez Pythona, aby zdecydować, że ciąg nie musi być dodany do swojej tabeli napisów, ale może być ponownie użyty. Jak widać na moim przykładzie, mechanizm ten nie dotyczy wszystkich równych łańcuchów, dlatego chciałbym zrozumieć, kiedy i jak jest używany. – dangonfast

+4

Możesz być zainteresowany [co ma na myśli Martijn Pieters] (https://www.codementor.io/python-tutorial/stack-overflow-martijn-pieters-python-optimization?utm_source = reddit-content & utm_medium = blog & utm_term = python-tutorial-python-internals & utm_content = blog & utm_campaign = reddit-content) – inspectorG4dget

Odpowiedz

0

Ponieważ pytanie ma kilka upvotes (choć jest to nieco z dwóch egzemplarzach), odpowiem tutaj moje oryginalne pytania (dzięki komentarze powyżej):

  1. Tak, sprawdza python całej zawartości tabeli wewnętrznej: ale tylko dla niektórych ciągów znaków, głównie tych, które mogą być również używane jako identyfikatory. Chodzi o to, że sztuczka przyśpieszenia używana do obsługi identyfikatorów przez interpreter python (kompilator?) Jest również przydatna do ogólnego zarządzania ciągami znaków. Proces ten nazywany jest interning
  2. O ile wiem, nie ma ograniczeń co do wielkości strun, ale istnieją inne zasady struny do ponownego wykorzystania (głównie: muszą wyglądać identyfikatorów Pythona)
  3. Tak, tabela jest normalnym pythonem, a łańcuchy mają skrót do wyszukiwania.
  4. Służy tylko do literałów ciągłych i wyrażeń stałych. Zasadniczo dla wszystkich rzeczy, które interpreter Pythona może wywnioskować podczas fazy kompilacji.

Aby wyjaśnić ostatni punkt, poniższe fragmenty ocenia się we wszystkich przypadkach jako ciąg 'xxx', ale są one traktowane inaczej w odniesieniu do interningu.

Jest stałym wyrażeniem:

'x' * 3 

Ale to nie jest:

a = 'x' 
a * 3 # this is no constant expression, so no interning can be applied. 

I to nie jest wyrażenie:

''.join(['x', 'x', 'x']) # this is no expression (a function is called) 
+0

Ta odpowiedź tylko zwiększa zamieszanie. '' x '* 3' jest ** nie ** literałem łańcuchowym, jest wyrażeniem. To, że wynik jest internowany, jest szczegółem implementacji, optymalizacją wykonaną przez kompilator, która wstępnie oblicza wyrażenia proste, takie jak '1 + 1' lub' 'x' * 3' podczas kompilacji. W przypadku łańcuchów stosuje się zwykłe połączenie ciągów, które wyglądają jak identyfikatory. Wyrażenia wprowadzane w interaktywnym monitorze przechodzą dokładnie tę samą ścieżkę do kompilacji, co pliki '.py'. – user4815162342

+0

@ user4815162342: więc jak wyjaśnić, że 'a = 'x'; a * 3' nie jest internowany? Jest to również wyrażenie, a wynikowy ciąg spełnia wszystkie wymagania dotyczące interwencji ... – dangonfast

+0

Jest to również wyrażenie, ale nie takie, które obejmuje tylko stałe. Obecny kompilator CPython nie jest wystarczająco inteligentny, aby udowodnić, że 'a * 3' jest w tym przypadku taki sam jak' 'x' * 3'. (W rzeczywistości składanie stałych w czasie kompilacji jest stosunkowo nowym dodatkiem do kompilatora, zaimplementowanym gdzieś w ramce czasowej 2.3-2.5, jeśli pamięć mi służy). – user4815162342

Powiązane problemy