Zawsze mnie to myliło. Wygląda na to, że byłoby to ładniejsze:
my_list = ["Hello", "world"]
print(my_list.join("-"))
# Produce: "Hello-world"
Od tego:
my_list = ["Hello", "world"]
print("-".join(my_list))
# Produce: "Hello-world"
Czy jest jakiś konkretny powód tego?
-
oświadcza, że dołączasz do listy i konwertujesz na ciąg znaków, który jest zorientowany na wyniki.str
niż zaimplementować ją na każdym typie iterowalnym.Odpowiedzi:
Wynika to z faktu, że dowolną iterowalną można połączyć (np. Listę, krotkę, dict, set), ale wynik i „łącznik” muszą być ciągami.
Na przykład:
Użycie czegoś innego niż ciągi spowoduje zgłoszenie następującego błędu:
źródło
list.join(string)
wydaje się bardziej podejściem zorientowanym obiektowo, podczas gdystring.join(list)
dla mnie brzmi o wiele bardziej proceduralnie.print(str.join('-', my_list))
i działa, czuje się lepiej.__iter__
metodę. Wymaganie również implementacji wszystkich iteratorówjoin
skomplikowałoby ogólny interfejs (który obejmuje także iteracje ponad ciągami) dla bardzo szczególnego przypadku użycia. Zdefiniowaniejoin
na strins bocznych kroków tego problemu kosztem „nieintuicyjnego” zamówienia. Lepszym wyborem mogłoby być zachowanie tej funkcji, przy czym pierwszym argumentem jest iterowalny, a drugim (opcjonalnym) łańcuchem łączącym - ale ten statek odpłynął.Zostało to omówione w metodach String ... w końcu wątek w Python-Dev osiągnął i został zaakceptowany przez Guido. Wątek ten rozpoczął się w czerwcu 1999 r. I
str.join
został zawarty w języku Python 1.6, który został wydany we wrześniu 2000 r. (I obsługuje Unicode). Python 2.0 (w tym obsługiwanestr
metodyjoin
) został wydany w październiku 2000 roku.str.join(seq)
seq.join(str)
seq.reduce(str)
join
jako wbudowana funkcjalist
s,tuple
s, ale wszystkie sekwencje / iterables.seq.reduce(str)
jest trudny dla początkujących.seq.join(str)
wprowadza nieoczekiwaną zależność od sekwencji do str / unicode.join()
jako wbudowana funkcja obsługiwałaby tylko określone typy danych. Dlatego używanie wbudowanej przestrzeni nazw nie jest dobre. Jeślijoin()
obsługuje wiele typów danych, utworzenie zoptymalizowanej implementacji byłoby trudne, jeśli zostało zaimplementowane przy użyciu__add__
metody, to jest to O (n²).sep
) nie powinien być pomijany. Jawne jest lepsze niż niejawne.W tym wątku nie ma innych powodów.
Oto kilka dodatkowych myśli (moich i mojego przyjaciela):
Decyzja Guido jest zapisana w historycznej przesyłce , która decyduje o
str.join(seq)
:źródło
Ponieważ
join()
metoda znajduje się w klasie łańcuchowej, zamiast w klasie listy?Zgadzam się, że to wygląda zabawnie.
Zobacz http://www.faqs.org/docs/diveintopython/odbchelper_join.html :
źródło
string
Bibliotekastr
języka Python 3 usunęła wszystkie zbędne metody, więc nie można już używaćstring.join()
. Osobiście nigdy nie myślałem, że to „zabawne”, ma to sens, ponieważ możesz dołączyć do czegoś więcej niż tylko list, ale łącznik jest zawsze ciągiem znaków!Zgadzam się, że na początku jest to sprzeczne z intuicją, ale jest dobry powód. Dołącz nie może być metodą listy, ponieważ:
Istnieją dwie metody łączenia (Python 3.0):
Jeśli join był metodą z listy, musiałby sprawdzić swoje argumenty, aby zdecydować, który z nich wywołać. I nie możesz łączyć bajtów i str razem, więc sposób, w jaki je mają, ma teraz sens.
źródło
Jest tak, ponieważ
join
jest to metoda „ciągowa”! Tworzy ciąg z dowolnego iterowalnego. Jeśli utknęliśmy metodę na listach, co powiesz na to, kiedy mamy iteracje, które nie są listami?Co jeśli masz krotkę sznurków? Gdyby to była
list
metoda, musiałbyś rzucić każdy taki iterator ciągów,list
zanim mógłbyś połączyć elementy w jeden ciąg! Na przykład:Rzućmy własną metodą łączenia listy:
I aby go użyć, należy pamiętać, że musimy najpierw utworzyć listę z każdej iterowalnej, aby dołączyć do niej ciągi znaków, marnując zarówno pamięć, jak i moc przetwarzania:
Widzimy więc, że musimy dodać dodatkowy krok, aby użyć naszej metody list, zamiast po prostu wbudowanej metody ciągu:
Ograniczenie wydajności dla generatorów
Algorytm, którego używa Python, aby utworzyć końcowy ciąg,
str.join
faktycznie musi dwukrotnie przejść przez iterowalny ciąg , więc jeśli podasz mu wyrażenie generujące, musi najpierw zmaterializować go na liście, zanim będzie mógł utworzyć końcowy ciąg.Tak więc, chociaż przekazywanie generatorów jest zwykle lepsze niż rozumienie list,
str.join
jest wyjątkiem:Niemniej jednak
str.join
operacja jest nadal semantycznie operacją „łańcuchową”, więc nadal warto mieć ją nastr
obiekcie niż na różnych iteracjach.źródło
Pomyśl o tym jak o naturalnej ortogonalnej operacji podziału.
Rozumiem, dlaczego ma zastosowanie do wszystkiego, co można iterować, więc nie można go łatwo wdrożyć tylko na liście.
Jeśli chodzi o czytelność, chciałbym zobaczyć to w języku, ale nie sądzę, aby było to w rzeczywistości wykonalne - gdyby iterowalność była interfejsem, mogłaby być dodana do interfejsu, ale jest to tylko konwencja, więc nie ma centralnego sposobu na dodaj go do zbioru rzeczy, które można iterować.
źródło
Przede wszystkim dlatego, że wynikiem a
someString.join()
jest ciąg znaków.Sekwencja (lista, krotka lub cokolwiek innego) nie pojawia się w wyniku, tylko ciąg znaków. Ponieważ wynikiem jest łańcuch, ma on sens jako metoda łańcucha.
źródło
-
w "-". join (moja_lista) deklaruje, że konwertujesz na ciąg z łączenia elementów w listę. Jest zorientowany na wyniki. (tylko dla łatwej pamięci i zrozumienia)Przygotowuję wyczerpujący zestaw metod z metody string dla twojego odniesienia.
źródło
Oba nie są miłe.
string.join (xs, delimit) oznacza, że moduł string jest świadomy istnienia listy, o której nie ma żadnej wiedzy biznesowej, ponieważ moduł string działa tylko z łańcuchami.
list.join (delimit) jest nieco ładniejszy, ponieważ jesteśmy tak przyzwyczajeni do ciągów znaków, które są podstawowym typem (a mówiąc językowo są). Oznacza to jednak, że sprzężenie musi być wywoływane dynamicznie, ponieważ w dowolnym kontekście
a.split("\n")
kompilatora python może nie wiedzieć, co to jest, i będzie musiało to sprawdzić (analogicznie do wyszukiwania w vtable), co jest drogie, jeśli wykonasz dużo czasy.jeśli kompilator środowiska wykonawczego Python wie, że lista jest wbudowanym modułem, może pominąć wyszukiwanie dynamiczne i bezpośrednio zakodować zamiar w kodzie bajtowym, w przeciwnym razie musi dynamicznie rozwiązać „łączenie” „a”, które może składać się z kilku warstw dziedziczenia na połączenie (ponieważ między połączeniami znaczenie łączenia mogło się zmienić, ponieważ python jest językiem dynamicznym).
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 taka nigdy nie możesz mieć spójnej abstrakcji, która nie stałaby się niezgodna z podstawowymi ideologiami, gdy zaczniesz je kleić razem bez owijania ich w pogląd zgodny z twoją ideologią. Wiedząc o tym, podejście Pythona jest bardziej elastyczne, ponieważ jest tańsze, od Ciebie zależy, czy zapłacisz więcej, aby wyglądało to „ładniej”, albo przez utworzenie własnego opakowania, albo własnego preprocesora.
źródło
Zmienne
my_list
i"-"
oba są obiektami. W szczególności są to instancje klaslist
istr
odpowiednio.join
Funkcja należy do klasystr
. Dlatego"-".join(my_list)
używana jest składnia, ponieważ obiekt"-"
przyjmujemy_list
dane wejściowe.źródło