Dlaczego% s jest lepszy od + do konkatenacji?


88

Rozumiem, że powinniśmy używać %sdo konkatenacji łańcucha zamiast +w Pythonie.

Mógłbym wykonać dowolną z następujących czynności:

hello = "hello"
world = "world"

print hello + " " + world
print "%s %s" % (hello, world)
print "{} {}".format(hello, world)
print ' '.join([hello, world])

Ale dlaczego miałbym używać czegoś innego niż +? Szybsze jest pisanie konkatenacji za pomocą prostego +. Następnie, jeśli spojrzeć na ciąg formatowania, można określić na przykład rodzaje %si %doraz takie. Rozumiem, że lepiej byłoby wyraźnie powiedzieć o typie.

Ale potem przeczytałem, że +należy unikać używania do konkatenacji, chociaż łatwiej jest pisać. Czy istnieje wyraźny powód, dla którego łańcuchy powinny być łączone na jeden z tych innych sposobów?


29
Kto ci powiedział, że lepiej?
yannis,

3
%sNie jest łączenie, to opis konwersji do formatowania łańcuch pochodzący z C na printf(3). Istnieją przypadki użycia tego lub operatora konkatenacji; których używasz, powinny opierać się na ocenie sytuacji, a nie dogmatach. To, jak łatwo jest napisać kod, jest całkowicie nieistotne, ponieważ zrobisz to tylko raz.
Blrfl,

Mam pytanie do skoncentrowanej tylko python (choć nie jestem osobą, python i nie może być jeszcze usterki w kodzie). Upewnij się, że jest to pytanie, które zadajesz, dokonaj odpowiednich aktualizacji i rozważ zadanie innego pytania, jeśli interesuje Cię C lub Java.

12
A teraz mamy lepsze stringi ! print(f"{hello} {world}"), ma czytelność konkatenacji, ponieważ zmienne są widoczne tam, gdzie występują w ciągu, i jest szybszy niż str.format.
Enrico Borba

Odpowiedzi:


88
  1. Czytelność. Składnia ciągu formatu jest bardziej czytelna, ponieważ oddziela styl od danych. Również w Pythonie, %sskładnia automatycznie wymusić żadnych innych niż strtypy na str; podczas gdy konkatenacja działa tylko z str, a nie możesz łączyć się strz int.

  2. Występ. W Pythonie strjest niezmienny, więc lewy i prawy ciąg należy skopiować do nowego ciągu dla każdej pary konkatenacji. Jeśli połączysz cztery ciągi o długości 10, będziesz kopiować (10 + 10) + ((10 + 10) +10) + (((10 + 10) +10) +10) = 90 znaków, a nie tylko 40 postacie. A wraz ze wzrostem liczby i rozmiaru struny sytuacja staje się kwadratowo gorsza. Java czasami optymalizuje ten przypadek, przekształcając serię konkatenacji do użycia StringBuilder, ale CPython nie.

  3. W niektórych przypadkach biblioteka rejestrująca udostępnia interfejs API, który używa lasera formatującego do leniwego tworzenia łańcucha wpisu dziennika ( logging.info("blah: %s", 4)). Jest to świetne dla poprawy wydajności, jeśli biblioteka rejestrująca zdecydowała, że ​​bieżący wpis dziennika zostanie odrzucony przez filtr dziennika, więc nie trzeba formatować łańcucha.


31
czy masz jakieś naukowe lub empiryczne źródło # 1? Ponieważ uważam, że jest o wiele mniej czytelny (szczególnie z więcej niż 2 lub 3 argumentami)
Lovis,

4
@ L.Möller: Nie jestem do końca pewien, jakiego źródła oczekujesz od tego, co ostatecznie jest subiektywnym doświadczeniem (łatwość czytania), ale jeśli chcesz moje rozumowanie: 1)% s wymaga 2 dodatkowych znaków na symbol zastępczy vs + wymaga minimum 4 (lub 8, jeśli podążasz za PEP8, 13, jeśli wymuszasz), 2)% s jest zamknięty w jednym ciągu, więc łatwiej jest parsować wizualnie, z +, masz więcej ruchomych części: zamknięty ciąg, operator, zmienna , operator, ciąg otwarty, 3) kolorowanie składni% s ma jeden kolor dla każdej funkcji: ciąg i symbol zastępczy, a + daje trzy kolory: ciąg, operator i zmienne zabarwienie.
Lie Ryan,

4
@ L.Möller: 4) Mam opcję umieszczania dłuższych ciągów formatu w zmiennej lub słowniku, z dala od miejsca, w którym należy wykonać formatowanie, 5) Ciąg formatu może być określony przez użytkownika z pliku konfiguracyjnego, argumentów polecenia lub bazy danych , tego samego nie można powiedzieć o konkatenacjach. Ale tak, nie używałbym również% s, gdy mam więcej niż 4-5 rzeczy do interpolacji, zamiast tego użyłbym wariantu% (varname) s lub „{foo}” .format () w Pythonie. Myślę, że wyraźne nazwy poprawiają czytelność dłuższych ciągów formatu z dużą ilością interpolowanych zmiennych.
Lie Ryan,

2
Nie wiem, co jest „prawdziwe”, dlatego pytam, czy masz dowody :-). Naprawdę zgadzam się z twoim drugim komentarzem
Lovis,

6
Uważam, że # 2 jest podejrzane - czy masz udokumentowane dowody? Nie znam się doskonale na Javie, ale w C # konkatenacja jest szybsza niż interpolacja łańcuchów . Całkowicie zgadzam się z numerem 1 i naprawdę polegam na tym przy podejmowaniu decyzji, kiedy tego użyć, ale musisz pamiętać, że interpolacja wymaga dużej ilości analizowania ciągów i złożoności, w której konkatenacja nie wymaga tego.
Jimmy Hoffa,

48

Czy jestem jedynym, który czyta od lewej do prawej?

Dla mnie używanie %sjest jak słuchanie niemieckiego mówcy, gdzie muszę poczekać do końca bardzo długiego zdania, aby usłyszeć, co to jest czasownik.

Który z nich jest szybszy na pierwszy rzut oka?

"your %s is in the %s" % (object, location)

lub

"your " + object + " is in the " + location  

17
Oczywiście jest to subiektywne, ponieważ uważam, że pierwszy jest bardziej czytelny - i łatwiejszy do napisania i edycji. Drugi przenika tekst z kodem, który przesłania oba i powoduje hałas. Na przykład łatwo jest pomylić spacje w sekundę.
JacquesB

5
@JacquesB Wydaje mi się, że twój mózg jest tak obeznany z tym formatem, że natychmiast przeskakujesz do nawiasów i natychmiast zastępujesz słowa. Technicznie rzecz biorąc, nie jest to czytanie od lewej do prawej, ale jest w porządku. Uważam, że też to robię, więc tak, 1 jest łatwiejszy do odczytania, ponieważ wiem, że mam do czynienia z głupimi problemami z odstępami przed i po cudzysłowach w drugim, i to jest naprawdę powolne.
Nelson

3
Po ndziesięcioleciach mój umysł też tak działa ;-) Ale nadal trzymam się mojej odpowiedzi, druga jest jaśniejsza i łatwiejsza do odczytania, dlatego też do utrzymania. A to staje się bardziej widoczne, im więcej masz parametrów. W końcu, jeśli jest to show dla jednego człowieka, idź z tym, co znasz i czujesz się komfortowo; jeśli jest to wysiłek zespołu, wymuszaj spójność i sprawdzaj kod; ludzie mogą się przyzwyczaić.
Mawg

4
Pierwszy jest dla mnie znacznie bardziej czytelny, ponieważ ma mniej „cruft” w środku zdania. Łatwiej jest mi spojrzeć do końca, a potem mózg analizuje dodatkowe cytaty, spacje i plusy. Oczywiście, teraz znacznie wolą Python formacie 3.6 ciągi: f"your {object} is in the {location}".
Dustin Wyatt

8
Jeszcze trudniej mi czytać i pisać, gdy zmienna musi być otoczona samymi cudzysłowami. "your '" + object + "' is in the '" + location + "'"... nie jestem nawet pewien, czy właśnie to teraz dostałem ...
Dustin Wyatt

12

Przykład wyjaśniający argument dotyczący czytelności:

print 'id: ' + id + '; function: ' + function + '; method: ' + method + '; class: ' + class + ' -- total == ' + total

print 'id: %s; function: %s; method: %s; class: %s --total == %s' % \
   (id, function, method, class, total)

(Pamiętaj, że drugi przykład jest nie tylko bardziej czytelny, ale także łatwiejszy do edycji, możesz zmienić szablon w jednym wierszu i listę zmiennych w innym)

Osobnym problemem jest to, że kod% s również konwertuje na ciąg, w przeciwnym razie musisz użyć wywołania str (), które jest również mniej czytelne niż kod% s.


1
Nie zgadzam się z twoim pierwszym oświadczeniem, ale możemy się zgodzić, że się różnią, właśnie miałem opublikować odpowiedź w stylu twojego drugiego, więc głosuj
Mawg

6

Korzystanie +powinien nie można uniknąć w ogóle. W wielu przypadkach jest to właściwe podejście. Używanie %slub .join()jest preferowane tylko w szczególnych przypadkach i zwykle jest to całkiem oczywiste, kiedy są lepszym rozwiązaniem.

W twoim przykładzie łączysz trzy ciągi razem, a użycie przykładu +jest wyraźnie najprostsze i najbardziej czytelne, a zatem zalecane.

%slub .format()są przydatne, jeśli chcesz interpolować ciągi lub wartości w środku większego ciągu. Przykład:

print "Hello %s, welcome to the computer!" % name

W takim przypadku użycie %sgo jest bardziej czytelne, ponieważ unikasz pocięcia pierwszego ciągu na wiele segmentów. Zwłaszcza jeśli interpolujesz wiele wartości.

.join() jest odpowiedni, jeśli masz sekwencję łańcuchów o zmiennej wielkości i / lub chcesz połączyć wiele łańcuchów z tym samym separatorem.


2

Ponieważ kolejność słów może się zmieniać w różnych językach, forma z %sjest niezbędna, jeśli chcesz poprawnie obsługiwać tłumaczenie ciągów w swoim oprogramowaniu.

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.