Python join: why is it string.join (list) zamiast list.join (string)?

To zawsze mnie myliło. Wygląda na to, że to byłoby ładniejsze:

my_list = ["Hello", "world"]
print my_list.join("-")
# Produce: "Hello-world"

Niż to:

my_list = ["Hello", "world"]
print "-".join(my_list)
# Produce: "Hello-world"

Czy Jest jakiś konkretny powód, dla którego tak jest?

Author: rrao, 2009-01-30

9 answers

Dzieje się tak dlatego, że można połączyć dowolne iterable, nie tylko listy, ale wynik i "joiner" są zawsze ciągami znaków.

Np:

import urllib2
print '\n############\n'.join(
    urllib2.urlopen('http://data.stackexchange.com/users/7095'))
 1036
Author: recursive,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-27 05:28:55

Ponieważ metoda join() jest w klasie string, a nie w klasie list?

Zgadzam się, że wygląda śmiesznie.

Zobacz http://www.faqs.org/docs/diveintopython/odbchelper_join.html :

Notka historyczna. Kiedy po raz pierwszy nauczyłem się Pythona, spodziewałem się, że join będzie metodą z listy, która zajęłaby ogranicznik jako argument. Dużo ludzie czują to samo i jest opowieść o metodzie łączenia. Prior do Pythona 1.6, ciągi nie mieć wszystko te użyteczne metody. Było oddzielny moduł Łańcuchowy, który zawierał wszystkie funkcje łańcuchowe; każdy funkcja wzięła łańcuch jako pierwszy kłótnia. Funkcje zostały uznane za wystarczająco ważne, aby umieścić na same struny, co miało sens dla funkcji takich jak dolna, górna i split. Ale wiele hard-core Python Programiści sprzeciwili się nowemu połączeniu metoda, argumentując, że powinno to być metoda listy zamiast, lub że to nie powinno się w ogóle ruszać, ale po prostu zostań część starego modułu string (który nadal ma wiele przydatnych rzeczy w nim). Używam wyłącznie nowej metody join, ale zobaczysz kod napisany albo sposób, a jeśli to naprawdę przeszkadza, ty można użyć starego Sznurka.funkcja join zamiast tego.

--- Mark Pilgrim, Dive into Python

 232
Author: Bill Karwin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-30 17:11:16

Zostało to omówione w metodach String... w końcu wątek w Pythonie-Dev achive i został zaakceptowany przez Guido. Ten wątek rozpoczął się w czerwcu 1999 roku, a str.join został włączony do Pythona 1.6, który został wydany we wrześniu 2000 roku (i obsługiwał Unicode). Python 2.0 (obsługiwane metody str, w tym join) został wydany w październiku 2000 roku.

  • w tym wątku zaproponowano Cztery opcje:
    • str.join(seq)
    • seq.join(str)
    • seq.reduce(str)
    • join jako wbudowany function
  • Guido chciał wspierać nie tylko list s, tuple S, ale wszystkie sekwencje / iterable.
  • seq.reduce(str) jest trudne dla nowych przybyszów.
  • seq.join(str) wprowadza nieoczekiwaną zależność od sekwencji do str / unicode.
  • join() jako wbudowana funkcja wspierałaby tylko określone typy danych. Więc używanie wbudowanej przestrzeni nazw nie jest dobre. Jeśli join() obsługuje wiele typów danych, stworzenie zoptymalizowanej implementacji byłoby trudne, gdyby została zaimplementowana przy użyciu metody __add__ wtedy jest O (n2).
  • separater string (sep) nie powinien być pomijany. Explicit jest lepszy niż implicit.

w tym wątku nie ma innych powodów.

Oto kilka dodatkowych myśli (moich własnych i moich przyjaciół):

  • wsparcie dla Unicode miało nadejść, ale nie było ostateczne. W tym czasie UTF-8 najprawdopodobniej miał zastąpić UCS2 / 4. Aby obliczyć całkowitą długość bufora łańcuchów UTF-8 należy znać kodowanie znaków zasada.
  • w tym czasie Python już zdecydował się na wspólną regułę interfejsu sekwencji, gdzie użytkownik mógł utworzyć klasę podobną do sekwencji (iterable). Ale Python nie obsługiwał rozszerzania wbudowanych typów aż do 2.2. W tym czasie trudno było dostarczyć podstawową klasę iterable (o czym jest mowa w innym komentarzu).

Decyzja Guido jest zapisana w historycznej wiadomości , decydując się na str.join(seq):

Zabawne, ale wydaje się słuszne! Barry, idź po to...
-- Guido van Rossum

 218
Author: Yoshiki Shibukawa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-06 15:46:14

Zgadzam się, że na początku jest to sprzeczne z intuicją, ale jest dobry powód. Join nie może być metodą listy, ponieważ:

  • musi działać również dla różnych iterabli (krotki, Generatory itp.)
  • musi mieć różne zachowania pomiędzy różnymi typami łańcuchów.

Istnieją dwie metody łączenia (Python 3.0):

>>> b"".join
<built-in method join of bytes object at 0x00A46800>
>>> "".join
<built-in method join of str object at 0x00A28D40>

Jeśli join jest metodą listy, to musiałaby sprawdzić swoje argumenty, aby zdecydować, który z nich ma zostać wywołany. I nie możesz połącz byte I str razem, więc sposób, w jaki je teraz mają, ma sens.

 59
Author: Kiv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-29 23:03:45

Dlaczego string.join(list) zamiast list.join(string)?

To dlatego, że join jest metodą "string"! Tworzy ciąg znaków z dowolnej iterowalnej. Jeśli umieścimy tę metodę na listach, to co jeśli mamy iterable, które nie są listami?

A jeśli masz krotkę sznurków? Gdyby była to metoda list, musiałbyś rzucić każdy taki iterator łańcuchów jako list, zanim mógłbyś połączyć elementy w jeden łańcuch! Na przykład:

some_strings = ('foo', 'bar', 'baz')

Let ' s roll our own list metoda łączenia:

class OurList(list): 
    def join(self, s):
        return s.join(self)
Aby go użyć, musimy najpierw utworzyć listę z każdego iterable, aby połączyć łańcuchy w iterable, marnując zarówno pamięć, jak i moc obliczeniową.]}
>>> l = OurList(some_strings) # step 1, create our list
>>> l.join(', ') # step 2, use our list join method!
'foo, bar, baz'

Widzimy więc, że musimy dodać dodatkowy krok, aby użyć naszej metody list, zamiast tylko używać wbudowanej metody string:

>>> ' | '.join(some_strings) # a single step!
'foo | bar | baz'

Zastrzeżenie wydajności dla generatorów

Algorytm używany przez Pythona do tworzenia końcowego ciągu z str.join faktycznie musi przejść przez iterowalne dwa razy, więc jeśli podasz mu wyrażenie generatora, musi najpierw zmaterializować go w listę, zanim będzie mógł utworzyć ostateczny ciąg znaków.

Dlatego, podczas gdy przekazywanie generatorów jest zwykle lepsze niż składanie list, str.join jest wyjątkiem:
>>> import timeit
>>> min(timeit.repeat(lambda: ''.join(str(i) for i in range(10) if i)))
3.839168446022086
>>> min(timeit.repeat(lambda: ''.join([str(i) for i in range(10) if i])))
3.339879313018173

Niemniej jednak, operacja str.join jest nadal semantycznie operacją "string", więc nadal ma sens posiadanie jej na obiekcie str niż na różnych iterabach.

 36
Author: Aaron Hall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-18 23:09:33

Pomyśl o tym jako o naturalnej operacji ortogonalnej podziału.

Rozumiem, dlaczego ma zastosowanie do wszystkiego iterowalnego i dlatego nie można go łatwo zaimplementować Tylko na liście.

Jeśli chodzi o czytelność, chciałbym zobaczyć ją w języku, ale nie sądzę, że jest to w rzeczywistości wykonalne - gdyby iteracyjność była interfejsem, to mogłaby zostać dodana do interfejsu, ale jest to tylko konwencja, więc nie ma centralnego sposobu, aby dodać ją do zestawu rzeczy, które są iteracyjne.

 23
Author: Andy Dent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-30 02:43:51

Przede wszystkim dlatego, że wynik someString.join() jest ciągiem znaków.

Sekwencja (lista lub krotka lub cokolwiek) nie pojawia się w wyniku, tylko ciąg znaków. Ponieważ wynikiem jest łańcuch, ma to sens jako metoda łańcucha.

 11
Author: S.Lott,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-29 22:51:45

- w " -".join (my_list) deklaruje, że konwertujesz na ciąg znaków z łączenia elementów a list.It zorientowane na wyniki.(tylko dla łatwej pamięci i zrozumienia)

Robię wyczerpujący arkusz cheatsheet methods_of_string w celach informacyjnych.

string_methonds_44 = {
    'convert': ['join','split', 'rsplit','splitlines', 'partition', 'rpartition'],
    'edit': ['replace', 'lstrip', 'rstrip', 'strip'],
    'search': ['endswith', 'startswith', 'count', 'index', 'find','rindex', 'rfind',],
    'condition': ['isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isnumeric','isidentifier',
                  'islower','istitle', 'isupper','isprintable', 'isspace', ],
    'text': ['lower', 'upper', 'capitalize', 'title', 'swapcase',
             'center', 'ljust', 'rjust', 'zfill', 'expandtabs','casefold'],
    'encode': ['translate', 'maketrans', 'encode'],
    'format': ['format', 'format_map']}
 3
Author: JawSaw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-22 10:10:02

Obie nie są miłe.

String.join (XS, delimit) oznacza, że moduł string jest świadomy istnienia listy, o której nie ma żadnej wiedzy, ponieważ moduł string działa tylko z łańcuchami.

Lista.join (delimit) jest nieco ładniejszy, ponieważ jesteśmy tak przyzwyczajeni do tego, że ciągi są typem podstawowym (i lingually speaking, one są). Oznacza to jednak, że join musi być wysyłany dynamicznie, ponieważ w dowolnym kontekście a.split("\n") kompilator Pythona może nie wiedzieć co to jest i będzie musiał to sprawdzić (analogicznie do Vtable lookup), co jest drogie, jeśli robisz to wiele razy.

Jeśli kompilator środowiska uruchomieniowego Pythona wie, że lista jest wbudowanym modułem, może pominąć dynamiczne wyszukiwanie i zakodować intencję bezpośrednio w kodzie bajtowym, podczas gdy w przeciwnym razie musi dynamicznie rozwiązać " join "z " a", które może mieć kilka warstw dziedziczenia na wywołanie(ponieważ pomiędzy wywołaniami znaczenie join może się zmienić, ponieważ python jest dynamicznym język).

Niestety, jest to ostateczna wada abstrakcji; bez względu na to, jaką abstrakcję wybierzesz, twoja abstrakcja będzie miała sens tylko w kontekście problemu, który próbujesz rozwiązać, i jako taki nigdy nie możesz mieć konsekwentnej abstrakcji, która nie stanie się niespójna z leżącymi u podstaw ideologiami, gdy zaczniesz je sklejać bez owijania w pogląd, który jest zgodny z Twoją ideologią. Wiedząc o tym, podejście Pythona jest bardziej elastyczne, ponieważ jest tańsze, to do ciebie należy zapłacenie więcej, aby wyglądało to "ładniej", tworząc własny wrapper lub własny preprocesor.

 2
Author: Dmitry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-07 19:41:39