วิธีเขียนสตริงที่ยาวมากซึ่งสอดคล้องกับ PEP8 และป้องกัน E501


203

เนื่องจาก PEP8 แนะนำให้รักษากฎคอลัมน์ 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."

แก้ไขในการสะท้อนฉันยอมรับว่าข้อเสนอแนะของ Todd วงเล็บใช้มากกว่าเส้นต่อเนื่องจะดีกว่าสำหรับเหตุผลทั้งหมดที่เขาให้ ความลังเลเพียงอย่างเดียวที่ฉันมีคือมันค่อนข้างง่ายที่จะทำให้สับสนกับวงเล็บ


4
นี่คือเหตุผลที่ฉันรู้สึกเหมือนคนงี่เง่าโพสต์คำถาม ไชโย
เฟเดอเรอร์

8
นี่คือความต่อเนื่องของบรรทัดโดยการหลีกเลี่ยงการต่อท้ายไม่ใช่เพียงการเชื่อมโยงโดยนัยและจนกว่าจะมีการห้ามอย่างชัดเจนเมื่อเร็ว ๆ นี้ใน PEP8 แม้ว่าตอนนี้จะมีการอนุญาต แต่ไม่ใช่สำหรับการตั้งค่าความยาว คำตอบของทอดด์ด้านล่างถูกต้อง
Aaron Hall

4
ฉันชอบ PEP8 แต่นี่เป็นส่วนหนึ่งของ PEP8 ที่ฉันไม่ชอบ ฉันรู้สึกเหมือนความต่อเนื่องโดยนัยมีความชัดเจนมากขึ้นเนื่องจากความเป็นไปได้ที่จะเกิดความสับสนกับสิ่งอันดับ
monknomo

1
อย่าลืมเพิ่มช่องว่างหลังจาก \
Mrinal Saurabh

เกิดอะไรขึ้นถ้าสายยาวอยู่ตรงกลางของสตริงหลายบรรทัดยาว?
Thayne

298

นอกจากนี้เนื่องจากค่าคงที่สตริงเพื่อนบ้านจะถูกต่อกันโดยอัตโนมัติคุณจึงสามารถเขียนโค้ดดังนี้:

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

ฉันใช้การค้นหาโดย Google ของ "python line length" ซึ่งส่งคืนลิงก์ PEP8 เป็นผลลัพธ์แรก แต่ยังเชื่อมโยงไปยังโพสต์ StackOverflow ที่ดีอื่นในหัวข้อนี้: " ทำไม Python PEP-8 ควรระบุความยาวบรรทัดสูงสุด 79 ตัวอักษร? "

ข้อความค้นหาที่ดีอีกข้อหนึ่งคือ "ความต่อเนื่องของสายหลาม"


8
+1: "โดยส่วนตัวแล้วฉันไม่ชอบแบ็กสแลชและฉันจำได้ว่าได้อ่านบางที่ว่าการใช้งานนั้นเลิกใช้งานจริงในรูปแบบนี้ซึ่งชัดเจนกว่านี้โปรดจำไว้ว่า" ชัดเจนดีกว่า implicit ""
Alberto Megía

13
สำหรับทุกคนที่ได้รับสิ่งอันดับและสงสัยว่าทำไม อย่าเพิ่มเครื่องหมายจุลภาคที่ท้ายบรรทัดที่นี่ซึ่งจะทำให้เกิด tuple ไม่ใช่สตริง ;)
bugmenot123

7
การเพิ่มตัวอักษร + ไม่ชัดเจนกว่าตัวอย่างที่ระบุหรือไม่ ฉันยังคงพิจารณาโดยปริยายนี้ เช่น"str1" + "str2"แทนที่จะเป็น"str1" "str2"
user1318135

4
ฉันเห็นด้วยว่าเครื่องหมายบวกนั้นชัดเจนกว่า แต่ก็ทำสิ่งที่แตกต่างออกไป มันเปลี่ยนสตริงเป็นนิพจน์ที่จะถูกประเมินแทนที่จะระบุค่าคงที่สตริงเดียวในจำนวนชิ้น ฉันไม่แน่ใจ แต่ฉันคิดว่านี่จะเกิดขึ้นในระหว่างการวิเคราะห์คำในขณะที่การแสดงออกต้องดำเนินการในภายหลัง ความแตกต่างของความเร็วอาจไม่ได้รับการยกเว้นเว้นแต่จะมีจำนวนมาก แต่ฉันก็ชอบการต่อข้อมูลแบบอัตโนมัติด้วยความสุนทรีย์เพราะมันเป็นตัวละครที่น้อยกว่าตัวอักษรต่อบรรทัด
ทอดด์

4
ไวยากรณ์นี้ยังคงมีความเป็นไปได้ของการใช้การจัดรูปแบบสตริงเช่น:('this is my really, really, really, really, really long {} ' 'that I'd really, really, really, like to {}').format(var1, var2))
Tim

16

ฉันคิดว่าคำที่สำคัญที่สุดในคำถามของคุณคือ "แนะนำ"

มาตรฐานการเข้ารหัสเป็นสิ่งที่ตลก บ่อยครั้งที่คำแนะนำที่พวกเขาให้นั้นมีพื้นฐานที่ดีจริง ๆ เมื่อถูกเขียน (เช่นเทอร์มินัลส่วนใหญ่ไม่สามารถแสดง> 80 ตัวอักษรในบรรทัด) แต่เมื่อเวลาผ่านไปพวกเขากลายเป็นหน้าที่ล้าสมัย แต่ยังยึดมั่นอย่างเหนียวแน่น ฉันเดาว่าสิ่งที่คุณต้องทำที่นี่คือการชั่งน้ำหนักข้อดีของการ "ทำลาย" คำแนะนำนั้นโดยเฉพาะกับความสามารถในการอ่านและ mainatinability ของรหัสของคุณ

ขออภัยนี่ไม่ได้ตอบคำถามของคุณโดยตรง


ฉันเห็นด้วยอย่างยิ่ง มีกฎสไตล์ Java ที่คล้ายคลึงกันซึ่งล้าสมัยเกินไป (IMHO)
Iker Jimenez

ใช่ฉันเห็นด้วย แต่มันทำให้ปวดหัวฉันจะปฏิบัติตามในตัวอย่างนี้ได้อย่างไร ฉันพยายามเก็บคลาสวิธีการ <80 ตัวอักษรเสมอ แต่ฉันจะบอกว่าสตริงแบบนี้ไม่มีผลกระทบใด ๆ
เฟเดอเรอร์

1
คุณต้องชั่งน้ำหนักความชอบส่วนตัวของคุณกับมาตรฐานการเข้ารหัสทั่วทั้งชุมชน คุณต้องการให้ผู้คนใหม่ ๆ เข้ามาและรู้สึกสบายใจกับการจัดรูปแบบโค้ดตั้งแต่วันแรก
retracile

1
ฉันรู้ว่าตัวฉันเองฉันมักจะติดกับขีด จำกัด ของตัวละคร 80 เพียงเพราะฉันยังคงทำส่วนใหญ่ของการเขียนโปรแกรมใน IDLE และฉันไม่ชอบวิธีการจัดการเลื่อนแนวนอน (ไม่มีแถบเลื่อน)
Tofystedeth

@retracile - ใช่คุณทำ ฉันไม่ได้พูดว่า "คุณต้องเพิกเฉยต่อคำแนะนำ" แทนที่จะแนะนำว่าในบางกรณีคำแนะนำนั้นไม่จำเป็นต้องมีเพื่อประโยชน์ของชุมชน ฉันไม่ได้ตระหนักถึงข้อ จำกัด ของ IDLE (ตามที่โพสต์โดย Tofystedeth) แต่ในกรณีนั้นมีอาร์กิวเมนต์ striong สำหรับทำตามการประชุม
ZombieSheep

13

คุณสูญเสียพื้นที่และคุณอาจต้องใช้อักขระต่อเนื่องบรรทัดเช่น ก\.

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

Parens จะทำงานแทนการต่อเนื่องของสาย แต่คุณเสี่ยงที่จะมีคนคิดว่าคุณตั้งใจจะมีสิ่งอันดับและเพิ่งลืมเครื่องหมายจุลภาค ยกตัวอย่างเช่น

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

หรือห่อใน parens:

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 ทำ (บีบอัด whitespace สองบรรทัดใหม่สำหรับย่อหน้าใหม่ไม่ต้องกังวลเกี่ยวกับช่องว่างระหว่างบรรทัด)

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

  • Blobs หลายบรรทัดข้อความมักจะมีโทเค็นที่จัดรูปแบบ (ไม่ใช่สิ่งที่คุณขอ แต่ยังมีประโยชน์):

    error_message = '''
    I generally like to see how my helpful, sometimes multi-line error
    messages will look against the left border.
    '''.strip()
  • เพิ่มตัวแปรทีละชิ้นด้วยวิธีการแก้ไขสตริงที่คุณต้องการ:

    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 ไม่ได้จำกัดความยาวของสตริงในไฟล์ เพียงบรรทัดของรหัสของคุณ :)

  • ใช้แรงเดรัจฉานหรือเครื่องมือแก้ไขของคุณเพื่อแยกสตริงเป็นบรรทัด managaeble โดยใช้บรรทัดใหม่แล้วลบบรรทัดใหม่ทั้งหมด (คล้ายกับเทคนิคแรกที่ฉันระบุไว้):

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

0

ตัวเลือกที่มี:

  • แบ็กสแลช :"foo" \ "bar"
  • เครื่องหมายบวกตามด้วยแบ็กสแลช :"foo" + \ "bar"
  • วงเล็บ :
    • ("foo" "bar")
    • วงเล็บที่มีเครื่องหมายบวก :("foo" + "bar")
    • PEP8, E502: แบ็กสแลชซ้ำซ้อนระหว่างวงเล็บ

หลีกเลี่ยงการ

หลีกเลี่ยงวงเล็บด้วยเครื่องหมายจุลภาค: ("foo", "bar")ซึ่งกำหนด tuple


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