PEP8に準拠した非常に長い文字列を記述してE501を防ぐ方法


203

PEP8がpythonプログラムの80列のルールを下回るように提案しているので、長い文字列を使用してどうすればそれを遵守できますか。

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

これを次の行に拡張するにはどうすればいいですか?

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

回答:


116

暗黙の連結が最もク​​リーンなソリューションである可能性があります。

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

エディットオンリフレクション私は、トッドが与えるすべての理由から、行の継続ではなくブラケットを使用するというトッドの提案の方が優れていることに同意します。唯一のためらいは、括弧で囲まれた文字列をタプルと混同するのは比較的簡単なことです。


4
これが私が馬鹿に質問を投稿するような気がした理由です。乾杯。
フェデラー

8
これは、単に暗黙の連結ではなく、最終行をエスケープすることによる行継続であり、ごく最近までPEP8で明示的に禁止されていましたが、現在は許可がありますが、長い文字列は許可されません。以下のトッドの答えは正しいです。
アーロンホール

4
私はPEP8が好きですが、これは私が好きではないPEP8の一部です。タプルとの混同の可能性があるため、暗黙の継続がより明確になっているように感じます
monknomo

1
\の後には空白スペースを追加しないでください
Mrinal Saurabh

長い行が長い複数行の文字列の中央にある場合はどうなりますか?
Thayne

299

また、隣接する文字列定数は自動的に連結されるため、次のようにコーディングすることもできます。

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

プラス記号がないことに注意してください。そして、例のフォーマットに続く余分なコンマとスペースを追加しました。

個人的に私はバックスラッシュが好きではありません。どこかで読んだことを覚えていますが、その使用は実際には推奨されておらず、この形式がより明示的であるためです。「明示的は暗黙的より優れている」ことを覚えておいてください。

これは実際には改行文字をエスケープしているため、バックスラッシュはあまり明確ではなく、あまり役に立たないと考えています。コメントが必要な場合は、コメントの後に行末コメントを付けることはできません。連結された文字列定数でこれを行うことができます:

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

私は、最初の結果としてPEP8リンクを返す「Pythonのラインの長さ」のGoogle検索を使用するだけでなく、このトピックの別の良いStackOverflowのポストへのリンクが:「なぜPythonのPEP8は、79文字の最大の行の長さを指定する必要がありますか?

別の優れた検索フレーズは、「python line continuation」です。


8
1:「個人的に私はバックスラッシュ好きではない、と私はその使用が実際より明示的であるこの形式の非推奨されていることをどこかに読んで思い出してください。 『明示的、暗黙的よりも優れている』」。
アルベルトMegía

13
タプルを取得し、その理由を疑問に思うすべての人のために。ここで行の最後にコンマを追加しないでください。追加すると、文字列ではなくタプルになります。;)
bugmenot123 2015

7
+文字を追加することは、与えられた例よりも明確ではありませんか?私はまだこれを暗黙のうちに考えています。つまり、"str1" + "str2"ではなく"str1" "str2"
user1318135

4
私は実際にはプラス記号がより明確であることに同意しますが、それは別のことをします。文字列定数を複数に分けて指定するのではなく、文字列を評価する式に変換します。確かではありませんが、これは解析中に行われると思いますが、式は後で実行する必要があります。それらの数が非常に多い場合を除き、速度の違いはおそらく無視できます。しかし、審美的には、自動連結を好んでいます。自動連結は、1行あたり1の雑然とした文字ではないからです。
トッド

4
この構文はまた、同様に、文字列の書式設定を適用する可能性を保持します:('this is my really, really, really, really, really long {} ' 'that I'd really, really, really, like to {}').format(var1, var2))
ティム・

16

あなたの質問で最も重要な言葉は「提案」だったと思います。

コーディング基準は面白いものです。多くの場合、それらが提供するガイダンスは、それが書かれたとき(たとえば、ほとんどの端末が1行に80文字以上を表示できない)、本当に良い基盤を持っていますが、時間が経つと機能的に陳腐化しますが、厳守されます。ここで行う必要があるのは、コードの可読性と保守性に対する特定の提案を「壊す」ことの相対的なメリットを比較検討することだと思います。

申し訳ありませんが、これはあなたの質問に直接回答しません。


全くもって同じ意見です。廃止された同様のJavaスタイルのルールもあります(IMHO)。
Iker Jimenez、

はい、同意します。ただし、この特定の例ではどのようにそれを順守するかが頭を悩ませています。私は常にクラス、メソッドを80文字未満に保つように努めていますが、このような文字列はおそらく負の文字列以外には効果がないと思います。
フェデラー

1
また、コミュニティ全体のコーディング標準に対して個人的な好みを比較検討する必要があります。新しい人が入ってきて、初日からコードのフォーマットに慣れることができるようにしたいとします。
遡及2009

1
自分自身については、IDLEでコーディングの大部分を行っているだけで、横スクロールの処理方法が気に入らないため、80文字の制限に固執する傾向があります。(スクロールバーなし)
Tofystedeth、2009

@retracile-はい、そうです。私は「あなたはガイダンスを無視しなければならない」と言っているのではなく、場合によってはコミュニティの利益のためにガイダンスが必ずしもそこにあるとは限らないことを示唆しています。私は(Tofystedethによって投稿された)IDLEの制限を認識していませんでしたが、その場合、規則に従うためのstriong引数があります。
ZombieSheep 09

13

スペースを失い、おそらく行継続文字が必要です。A \

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

あるいは:

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

行の継続の代わりに括弧も機能しますが、タプルを作成するつもりでコンマを忘れたと思ってしまう危険性があります。例えば:

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

対:

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

Pythonの動的型付けでは、コードはどちらの方法でも実行できますが、意図していないものを使用すると誤った結果が生成されます。


2

バックスラッシュ:

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

または括弧で囲む:

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

2
プラスが必要であることに注意してください。Pythonは、互いに続く文字列リテラルを連結します。
bukzor

2

これらはすべて素晴らしい答えですが、「暗黙的に連結された」文字列の編集に役立つエディタープラグインを見つけることができなかったので、簡単にできるようにパッケージを作成しました。

この古いスレッドをさまよっている人がチェックしたい場合は、pip(段落のインストール)で。htmlと同じように複数行の文字列をフォーマットします(空白、新しい段落の2つの改行、行間のスペースの心配はありません)。

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")

になる...

__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.

すべてが(Vim) 'gq'と簡単に並びます


0

a \を使用すると、ステートメントを複数行に展開できます。

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

うまくいくはずです。


0

大きな文字列を指定するために、ここに記載されていないいくつかのメソッドを使用する傾向がありますが、これらは非常に特定のシナリオ用です。YMMV ...

  • テキストの複数行のblob、多くの場合はフォーマットされたトークン(要求されたものとは異なりますが、それでも有用です):

    error_message = '''
    I generally like to see how my helpful, sometimes multi-line error
    messages will look against the left border.
    '''.strip()
  • 任意の文字列補間方法を使用して、変数を1つずつ増やします。

    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.'
  • ファイルから読み取ります。PEP-8は、ファイル内の文字列の長さを制限しません。コードの行だけです。:)

  • ブルートフォースまたはエディタを使用して、改行を使用して文字列を扱いやすい行に分割し、すべての改行を削除します。(私がリストした最初のテクニックと同様):

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

0

利用可能なオプション:

  • バックスラッシュ"foo" \ "bar"
  • プラス記号とそれに続くバックスラッシュ"foo" + \ "bar"
  • ブラケット
    • ("foo" "bar")
    • 括弧付きプラス記号("foo" + "bar")
    • PEP8、E502:ブラケットの間のバックスラッシュは冗長です

避ける

("foo", "bar")タプルを定義するカンマで角括弧を避けます。


>>> 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

長い文字列リテラルを挿入する必要があり、flake8をシャットダウンしたい場合は、シャットダウンディレクティブを使用できます。たとえば、テストルーチンで、偽のCSV入力を定義しました。行のある行よりも多くの行に分割すると混乱を招く可能性があるため# noqa: E501、次のようにを追加することにしました。

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

過去にtextwrap.dedentを使用しました。これは少し面倒なので、今は行の継続を好みますが、本当にブロックのインデントが必要なのであれば、これはすばらしいと思います。

コード例(トリムはスライスで最初の '\ n'を取り除くことです):

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

説明:

dedentは、新しい行の前のテキストの最初の行の空白に基づいてインデントを計算します。微調整したい場合は、reモジュールを使用して簡単に再実装できます。

この方法には、非常に長い行が必要以上に長くなる場合があるという制限があります。その場合、文字列を連結する他の方法の方が適しています。


1
最初の改行を避けるために、x[1:]後でトリミングするのではなく、バックスラッシュを置くことができx = """ます。
Michael Dunn
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.