Jak napisać bardzo długi ciąg znaków, który jest zgodny z PEP8 i zapobiega E501


203

Jak PEP8 sugeruje trzymanie poniżej reguły 80 kolumn dla twojego programu python, jak mogę to zrobić z długimi łańcuchami, tj.

s = "this is my really, really, really, really, really, really, really long string that I'd like to shorten."

Jak mógłbym przejść do rozszerzenia tego do następującej linii, tj

s = "this is my really, really, really, really, really, really" + 
    "really long string that I'd like to shorten."

Odpowiedzi:


116

Niejawna konkatenacja może być najczystszym rozwiązaniem:

s = "this is my really, really, really, really, really, really," \
    " really long string that I'd like to shorten."

Edytuj Po refleksji Zgadzam się, że sugestia Todda, aby używać nawiasów zamiast kontynuacji linii, jest lepsza z wszystkich powodów, które podaje. Jedyne wahanie, jakie mam, to to, że stosunkowo łatwo pomylić łańcuchy z krotkami.


4
Właśnie dlatego czułem się jak idiota, który zadaje pytanie. Twoje zdrowie.
Federer,

8
Jest to kontynuacja linii przez ucieczkę od linii końcowej, a nie tylko domniemane konkatenacje, i do niedawna była wyraźnie zabroniona w PEP8, chociaż teraz istnieje tolerancja, ale NIE dla długich łańcuchów. Poniższa odpowiedź Todda jest poprawna.
Aaron Hall

4
Lubię PEP8, ale to część PEP8, której nie lubię.
Wydaje

1
Pamiętaj, aby nie dodawać żadnych spacji po \
Mrinal Saurabh

co jeśli długa linia znajduje się w środku długiego wieloliniowego ciągu?
Thayne

298

Ponadto, ponieważ sąsiednie stałe ciągów są automatycznie łączone, możesz również kodować w ten sposób:

s = ("this is my really, really, really, really, really, really, "  
     "really long string that I'd like to shorten.")

Zauważ, że nie ma znaku plus, a ja dodałem dodatkowy przecinek i spację, które następują po sformatowaniu twojego przykładu.

Osobiście nie lubię ukośników odwrotnych i przypominam sobie gdzieś, że jego użycie jest przestarzałe na rzecz tej formy, która jest bardziej wyraźna. Pamiętaj „Jawne jest lepsze niż niejawne”.

Uważam, że odwrotny ukośnik jest mniej wyraźny i mniej użyteczny, ponieważ w rzeczywistości ucieka on od znaku nowej linii. Jeśli to konieczne, nie można wstawić komentarza na końcu wiersza. Można to zrobić za pomocą połączonych stałych łańcuchowych:

s = ("this is my really, really, really, really, really, really, " # comments ok
     "really long string that I'd like to shorten.")

Użyłem wyszukiwarki Google „długość linii python”, która jako pierwszy wynik zwraca link PEP8, ale także linki do innego dobrego postu StackOverflow na ten temat: „ Dlaczego Python PEP-8 powinien określać maksymalną długość linii wynoszącą 79 znaków?

Inną dobrą frazą wyszukiwania byłaby „kontynuacja linii python”.


8
+1: „Osobiście nie lubię ukośników odwrotnych i przypominam sobie gdzieś, że jego użycie jest w rzeczywistości przestarzałe na rzecz tej formy, która jest bardziej wyraźna. Pamiętaj:„ Jawne jest lepsze niż niejawne. ””
Alberto Megía,

13
Dla każdego, kto dostaje krotkę i zastanawia się, dlaczego. Nie dodawaj przecinków na końcu linii, ponieważ spowoduje to krotkę, a nie ciąg znaków. ;)
bugmenot123

7
Czy dodanie znaku + nie jest wyraźniejsze niż w podanym przykładzie? Nadal uważam to za dorozumiane. tj. "str1" + "str2"zamiast"str1" "str2"
użytkownik1318135

4
Zgadzam się, że znak plus jest bardziej wyraźny, ale robi coś innego. Przekształca łańcuch w wyrażenie, które ma zostać ocenione, zamiast określać stałą jednego łańcucha w kilku częściach. Nie jestem pewien, ale myślę, że dzieje się to podczas analizy, podczas gdy wyrażenie musi zostać wykonane później. Różnica prędkości jest prawdopodobnie znikoma, chyba że jest ich ogromna liczba. Ale także pod względem estetycznym wolę automatyczną konkatenację, ponieważ jest to jeden mniej niepotrzebny znak na linię.
Todd,

4
Ta składnia zachowuje również możliwość stosowania formatowania ciągów, takich jak:('this is my really, really, really, really, really long {} ' 'that I'd really, really, really, like to {}').format(var1, var2))
Tim

16

Myślę, że najważniejszym słowem w twoim pytaniu było „sugeruje”.

Standardy kodowania to śmieszne rzeczy. Często dostarczane przez nich wskazówki mają naprawdę dobrą podstawę (np. Większość terminali nie jest w stanie wyświetlić> 80 znaków w linii), ale z czasem stają się przestarzałe funkcjonalnie, ale nadal są ściśle przestrzegane. Wydaje mi się, że powinieneś tutaj wyważyć względne zalety „przełamania” tej konkretnej sugestii w stosunku do czytelności i możliwości kodowania twojego kodu.

Przepraszamy, to nie odpowiada bezpośrednio na twoje pytanie.


W pełni się zgadzam. Istnieje podobna reguła w stylu Java, która również stała się nieaktualna (IMHO).
Iker Jimenez,

Tak, zgadzam się, jednak w tym konkretnym przykładzie dręczyło mnie to, jak bym sobie z tym poradził. Zawsze staram się zachować klasy, metody do <80 znaków, jednak powiedziałbym, że taki ciąg nie ma innego efektu niż być może negatywny.
Federer,

1
Musisz także porównać swoje osobiste preferencje ze standardem kodowania obowiązującym w całej społeczności. Chcesz, aby nowe osoby mogły wchodzić i czuć się swobodnie dzięki formatowaniu kodu od pierwszego dnia.
retracile

1
Wiem dla siebie, zwykle trzymam się limitu 80 znaków tylko dlatego, że nadal wykonuję większość kodowania w IDLE i nie podoba mi się sposób, w jaki obsługuje przewijanie w poziomie. (Bez paska przewijania)
Tofystedeth,

@retracile - tak, robisz. Nie mówię: „Musisz zignorować wytyczne”, raczej sugeruję, że w niektórych przypadkach wytyczne niekoniecznie służą dobru społeczności. Nie byłem świadomy ograniczeń IDLE (opublikowanych przez Tofystedeth), ale w tym przypadku istnieje argument striong za przestrzeganiem konwencji.
ZombieSheep,

13

Straciłeś spację i prawdopodobnie potrzebujesz znaku kontynuacji linii, tj. \.

s = "this is my really, really, really, really, really, really" +  \
    " really long string that I'd like to shorten."

lub nawet:

s = "this is my really, really, really, really, really, really"  \
    " really long string that I'd like to shorten."

Parens również działałyby zamiast kontynuacji linii, ale ryzykujesz, że ktoś pomyśli, że masz krotkę i właśnie zapomniałeś przecinka. Weź na przykład:

s = ("this is my really, really, really, really, really, really"
    " really long string that I'd like to shorten.")

przeciw:

s = ("this is my really, really, really, really, really, really",
    " really long string that I'd like to shorten.")

Dzięki dynamicznemu pisaniu w Pythonie kod może działać w obie strony, ale generować niepoprawne wyniki z tym, którego nie zamierzałeś.


2

Ukośnik wsteczny:

s = "this is my really, really, really, really, really, really" +  \
    "really long string that I'd like to shorten."

lub zawiń pareny:

s = ("this is my really, really, really, really, really, really" + 
    "really long string that I'd like to shorten.")

2
Pamiętaj, że plus jest konieczny. Python łączy literały łańcuchowe, które następują po sobie.
bukzor

2

To są świetne odpowiedzi, ale nie mogłem znaleźć wtyczki edytora, która pomogłaby mi w edycji ciągów „niejawnie połączonych”, więc napisałem pakiet, aby to dla mnie łatwiejsze.

Na pip (zainstaluj akapity), jeśli ktokolwiek błąka się po tym starym wątku, chciałby to sprawdzić. Formatuje ciągi wielowierszowe tak, jak robi to HTML (kompresuj białe znaki, dwie nowe linie dla nowego akapitu, nie martw się spacjami między wierszami).

from paragraphs import par


class SuddenDeathError(Exception):
    def __init__(self, cause: str) -> None:
        self.cause = cause

    def __str__(self):
        return par(
            f""" Y - e - e - e - es, Lord love you! Why should she die of
            {self.cause}? She come through diphtheria right enough the year
            before. I saw her with my own eyes. Fairly blue with it, she
            was. They all thought she was dead; but my father he kept ladling
            gin down her throat till she came to so sudden that she bit the bowl
            off the spoon. 

            What call would a woman with that strength in her have to die of
            {self.cause}? What become of her new straw hat that should have
            come to me? Somebody pinched it; and what I say is, them as pinched
            it done her in."""
        )


raise SuddenDeathError("influenza")

staje się ...

__main__.SuddenDeathError: Y - e - e - e - es, Lord love you! Why should she die of influenza? She come through diphtheria right enough the year before. I saw her with my own eyes. Fairly blue with it, she was. They all thought she was dead; but my father he kept ladling gin down her throat till she came to so sudden that she bit the bowl off the spoon.

What call would a woman with that strength in her have to die of influenza? What become of her new straw hat that should have come to me? Somebody pinched it; and what I say is, them as pinched it done her in.

Wszystko łatwo zrówna się z (Vim) „gq”


0

Za pomocą \można rozwinąć instrukcje do wielu wierszy:

s = "this is my really, really, really, really, really, really" + \
"really long string that I'd like to shorten."

powinno działać.


0

Zwykle używam kilku metod nie wymienionych tutaj do określania dużych ciągów, ale są to dla bardzo specyficznych scenariuszy. YMMV ...

  • Wieloliniowe obiekty BLOB tekstu, często ze sformatowanymi tokenami (niezupełnie o co prosiłeś, ale wciąż przydatne):

    error_message = '''
    I generally like to see how my helpful, sometimes multi-line error
    messages will look against the left border.
    '''.strip()
  • Rozwijaj zmienną kawałek po kawałku za pomocą dowolnej metody interpolacji ciągów:

    var = 'This is the start of a very,'
    var = f'{var} very long string which could'
    var = f'{var} contain a ridiculous number'
    var = f'{var} of words.'
  • Przeczytaj to z pliku. PEP-8 nie ogranicza długości ciągów w pliku; tylko linie kodu. :)

  • Użyj narzędzia Brute-Force lub edytora, aby podzielić ciąg na linie managaeble przy użyciu nowych linii, a następnie usuń wszystkie nowe linie. (Podobnie do pierwszej wymienionej przeze mnie techniki):

    foo = '''
    agreatbigstringthatyoudonotwanttohaveanyne
    wlinesinbutforsomereasonyouneedtospecifyit
    verbatimintheactualcodejustlikethis
    '''.replace('\n', '')

0

Dostępne opcje:

  • ukośnik odwrotny :"foo" \ "bar"
  • znak plus, po którym następuje odwrotny ukośnik :"foo" + \ "bar"
  • nawiasy :
    • ("foo" "bar")
    • nawiasy ze znakiem plus :("foo" + "bar")
    • PEP8, E502: ukośnik jest nadmiarowy między nawiasami

Uniknąć

Unikaj nawiasów przecinkowych: ("foo", "bar")definiuje krotkę.


>>> s = "a" \
... "b"
>>> s
'ab'
>>> type(s)
<class 'str'>
>>> s = "a" + \
... "b"
>>> s
'ab'
>>> type(s)
<class 'str'>
>>> s = ("a"
... "b")
>>> type(s)
<class 'str'>
>>> print(s)
ab
>>> s = ("a",
... "b")
>>> type(s)
<class 'tuple'>
>>> s = ("a" + 
... "b")
>>> type(s)
<class 'str'>
>>> print(s)
ab
>>> 

0

Jeśli musisz wstawić literał długiego łańcucha i chcesz, aby flake8 się zamknął, możesz użyć jego dyrektyw zamykających . Na przykład w procedurze testowania zdefiniowałem fałszywe dane CSV. Przekonałem się, że podzielenie go na więcej wierszy niż wierszy byłoby bardzo mylące, dlatego postanowiłem dodać, # noqa: E501co następuje:

csv_test_content = """"STATION","DATE","SOURCE","LATITUDE","LONGITUDE","ELEVATION","NAME","REPORT_TYPE","CALL_SIGN","QUALITY_CONTROL","WND","CIG","VIS","TMP","DEW","SLP","AA1","AA2","AY1","AY2","GF1","MW1","REM"
"94733099999","2019-01-03T22:00:00","4","-32.5833333","151.1666666","45.0","SINGLETON STP, AS","FM-12","99999","V020","050,1,N,0010,1","22000,1,9,N","025000,1,9,9","+0260,1","+0210,1","99999,9","24,0000,9,1",,"0,1,02,1","0,1,02,1","01,99,1,99,9,99,9,99999,9,99,9,99,9","01,1","SYN05294733 11/75 10502 10260 20210 60004 70100 333 70000="
"94733099999","2019-01-04T04:00:00","4","-32.5833333","151.1666666","45.0","SINGLETON STP, AS","FM-12","99999","V020","090,1,N,0021,1","22000,1,9,N","025000,1,9,9","+0378,1","+0172,1","99999,9","06,0000,9,1",,"0,1,02,1","0,1,02,1","03,99,1,99,9,99,9,99999,9,99,9,99,9","03,1","SYN04294733 11/75 30904 10378 20172 60001 70300="
"94733099999","2019-01-04T22:00:00","4","-32.5833333","151.1666666","45.0","SINGLETON STP, AS","FM-12","99999","V020","290,1,N,0057,1","99999,9,9,N","020000,1,9,9","+0339,1","+0201,1","99999,9","24,0000,9,1",,"0,1,02,1","0,1,02,1",,"02,1","SYN05294733 11970 02911 10339 20201 60004 70200 333 70000="
"94733099999","2019-01-05T22:00:00","4","-32.5833333","151.1666666","45.0","SINGLETON STP, AS","FM-12","99999","V020","200,1,N,0026,1","99999,9,9,N","000100,1,9,9","+0209,1","+0193,1","99999,9","24,0004,3,1",,"1,1,02,1","1,1,02,1","08,99,1,99,9,99,9,99999,9,99,9,99,9","51,1","SYN05294733 11/01 82005 10209 20193 69944 75111 333 70004="
"94733099999","2019-01-08T04:00:00","4","-32.5833333","151.1666666","45.0","SINGLETON STP, AS","FM-12","99999","V020","070,1,N,0026,1","22000,1,9,N","025000,1,9,9","+0344,1","+0213,1","99999,9","06,0000,9,1",,"2,1,02,1","2,1,02,1","04,99,1,99,9,99,9,99999,9,99,9,99,9","02,1","SYN04294733 11/75 40705 10344 20213 60001 70222="
"""  # noqa: E501

-1

W przeszłości korzystałem z textwrap.dedent. Jest to trochę kłopotliwe, więc wolę teraz kontynuację linii, ale jeśli naprawdę chcesz wcięcia blokowe, myślę, że to świetnie.

Przykładowy kod (gdzie wykończeniem jest pozbycie się pierwszego „\ n” plasterkiem):

import textwrap as tw
x = """\
       This is a yet another test.
       This is only a test"""
print(tw.dedent(x))

Wyjaśnienie:

dedent oblicza wcięcie na podstawie białej spacji w pierwszym wierszu tekstu przed nowym wierszem. Jeśli chcesz go ulepszyć, możesz łatwo go zaimplementować za pomocąre modułu.

Ta metoda ma ograniczenia w tym, że bardzo długie linie mogą być jeszcze dłuższe niż chcesz, w którym to przypadku inne metody konkatenacji łańcuchów są bardziej odpowiednie.


1
Zamiast przycinania za pomocą x[1:]można wstawić ukośnik odwrotny, x = """aby uniknąć pierwszej nowej linii.
Michael Dunn,
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.