Python Auto Formatter: Autopep8 vs. Black (และเคล็ดลับการปฏิบัติ)

Dec 12 2022
ข้อสรุปคือ: ฉันชอบสีดำเป็นเครื่องมือจัดรูปแบบอัตโนมัติ แต่มีเคล็ดลับเชิงปฏิบัติ (ในตอนท้าย) ที่คุณควรจำไว้ และทำงานได้ดีที่สุดควบคู่ไปกับเครื่องมืออื่นๆ เช่น isort บทนำ Autopep8 และ Black เป็นเครื่องมือที่ยอดเยี่ยมในการจัดรูปแบบโค้ด Python ของคุณโดยอัตโนมัติเพื่อให้สอดคล้องกับคู่มือสไตล์ PEP 8
การถ่ายภาพโดยผู้เขียน

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

บทนำ

Autopep8และBlackเป็นเครื่องมือที่ยอดเยี่ยมในการจัดรูปแบบโค้ด Python ของคุณโดยอัตโนมัติเพื่อให้สอดคล้องกับแนวทางสไตล์PEP 8 Black มี 30.4k ดาวบน GitHub และน่าจะเป็นเครื่องมือที่ได้รับความนิยมมากที่สุดในประเภทเดียวกัน ในขณะที่ autopep8 มี 4.2k ดาว

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

ฉันใช้ทั้งสองเครื่องมือในการทำงานของฉัน และฉันต้องการแบ่งปันกับคุณว่าทำไมฉันถึงชอบสีดำมากกว่า autopep8

ปัญหาเกี่ยวกับ autopep8

1. จัดเรียงการนำเข้าอย่างจริงจัง

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

ลองพิจารณาตัวอย่างด้านล่าง แม้ว่าsys.path.appendโดยทั่วไปจะไม่ใช่แนวปฏิบัติที่ดี แต่สมมติว่าเราต้องการทำอะไรบางอย่างก่อนที่จะนำเข้าโมดูลที่เหลือ

Autopep8 จะเขียนสคริปต์ใหม่ดังต่อไปนี้:

และนี่เป็นปัญหา อีกตัวอย่างหนึ่งที่ฉันคิดได้ก็คือ หากเราต้องการเปิดใช้งานแบ็กเอนด์ของ matplotlib สำหรับเทอร์มินัล linux เราจะต้องตั้งค่าแบ็กเอนด์matplotlib.use("agg") ก่อนที่จะfrom matplotlib import pyplot as plt นำ เข้าpyplot

ในทางตรงกันข้าม สีดำจะไม่เปลี่ยนโค้ดตัวอย่างด้านบน สีดำจะจัดรูปแบบเท่านั้นและความหมายของรหัสยังคงเหมือนเดิมทุกประการ กล่าวอีกนัยหนึ่ง สีดำไม่ได้จัดเรียงการนำเข้าของคุณ และไม่เปลี่ยนลำดับของรหัสของคุณ (และเราสามารถปล่อยให้งานคัดแยกการนำเข้าสำหรับเครื่องมือที่ยอดเยี่ยมอีกisortโปรดอ่านต่อ!)

คุณยังสามารถแก้ปัญหาได้โดยเพิ่ม# nopep8ส่วนย่อยของโค้ดของคุณ โดยบอกให้ autopep8 อย่างชัดเจนว่าอย่าแตะต้อง:

มันใช้งานได้ในกรณีนี้ แต่ฉันพบว่า# nopep8กฎการยกเว้นไม่ได้ใช้กับความคิดเห็น เช่น autopep8 จะยังคงแปลงสิ่งต่อไปนี้### some comment # nopep8เป็น# some comment # nopep8.

ในทางกลับกัน สีดำจะไม่แก้ไขความคิดเห็นและเอกสารคำสอน และคุณสามารถแยกโค้ดบางส่วนของคุณออกจากการจัดรูปแบบได้โดยเพิ่มบรรทัดความคิดเห็นสองบรรทัด# fmt: offและ# fmt: onก่อนและหลังโค้ดบล็อคของคุณ

อย่างไรก็ตาม มันไม่ใช่ Pythonic ใช่ไหม?

2. ไม่บังคับเยื้องอย่างถูกต้อง

การเยื้องเริ่มต้นของ Autopep8 ถูกตั้งค่าให้เหมือนกันกับขนาดแท็บของตัวแก้ไข และคุณสามารถระบุค่าได้โดยส่งตัวautopep8 --indent-size 4 myfile.pyเลือก ทั้งหมดเป็นสิ่งที่ดี แต่ autopep8 เฉพาะค่าอินพุตนี้เพื่อตั้งค่าการเยื้องสำหรับจุดเริ่มต้นของแต่ละคำสั่ง แต่ขนาดการเยื้องภายในวงเล็บจะถูกตั้งค่าเป็นขนาดแท็บเริ่มต้นเสมอ

ลองดูตัวอย่างนี้ โดยที่การเยื้องโค้ดคือ 1 และขนาดแท็บเริ่มต้นของตัวแก้ไขของฉันคือ 4

หลังจากตั้งค่าการเยื้องเป็น 3 ด้วย autopep8 autopep8 --indent-size 3 format_02_raw.py -i (-i หมายถึงในสถานที่)เราได้รับสิ่งต่อไปนี้:

เราจะเห็นว่าการเยื้องในฟังก์ชันแรกถูกตั้งค่าอย่างถูกต้องเป็น 3 แต่สิ่งที่อยู่ในวงเล็บ (ในกรณีนี้คือคำสั่งการพิมพ์และเมทริกซ์) จะถูกตั้งค่าเป็นขนาดแท็บเริ่มต้นแทน 4

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

การใช้สีดำให้ถูกวิธี

สีดำใช้สไตล์ของตัวเองซึ่งบางคนชอบและบางคนไม่ชอบ ฉันค่อนข้างชอบมันเพราะโดยทั่วไปมันสะอาดและอ่านง่าย แต่มีสองสิ่งที่ควรจำไว้

1. ใช้เครื่องหมายจุลภาคต่อท้าย

ตัวอย่างด้านล่างอาจเป็นหนึ่งในสาเหตุที่พบบ่อยที่สุดที่ทำให้คนบางคนไม่ชอบสีดำ มาดูก่อนและหลังกัน:

มันน่ารำคาญ แต่ก่อนที่คุณจะโกรธ เรามาเปลี่ยนแปลงโค้ดเล็กน้อยและดูว่าสีดำเปลี่ยนพฤติกรรมของมันอย่างไร:

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

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

เคล็ดลับโบนัส: เมื่อฉันเขียนแบบสอบถาม SQL ฉันจะเขียน

SELECT column_a
      ,column_b
      ,column_c
FROM some_table

SELECT column_a,
       column_b,
       column_c
FROM some_table

2. ระบุความยาวของบรรทัดหากจำเป็น

สิ่งเดียวที่ฉันไม่ชอบเกี่ยวกับสไตล์โค้ดสีดำจนถึงตอนนี้คือเกี่ยวกับคำสั่ง if ที่ยาว ดังตัวอย่างด้านล่างที่แสดง:

มันบังคับใช้ความสอดคล้อง แต่เสียสละการอ่าน ความยาวบรรทัดเริ่มต้นของ Black คือ 88 แต่บางครั้งฉันมีคำสั่งที่ยาวกว่านั้นเล็กน้อย และฉันไม่ต้องการให้จัดรูปแบบแบบนั้น

วิธีแก้ปัญหาของฉันคืออนุญาตให้มีความยาวบรรทัดที่ยาวขึ้นเล็กน้อย เราสามารถระบุความยาวบรรทัดโดยใช้--line-lengthหรือ-lแฟล็ก และถ้าเราตั้งค่าความยาวบรรทัดเป็น 100 black -l 100 format_05_raw.pyตัวอย่างข้างต้นจะไม่ถูกจัดรูปแบบใหม่ จากประสบการณ์ของผม ความยาวบรรทัด 100 บรรทัดจะเหมาะกับข้อความที่ยาวที่สุดในขณะที่ยังคงรักษาความสามารถในการอ่านโค้ดได้ดี (แม้ว่าคุณควรพิจารณาเขียนข้อความใหม่หากยาวเกิน 100 อักขระ) แต่แน่นอนว่านี่ขึ้นอยู่กับแต่ละทีมที่จะตัดสินใจ .

Autopep8 มีแฟล็กดังกล่าวด้วย--max-line-lengthอย่างไรก็ตาม เนื่องจาก autotpep8 มีแนวโน้มที่จะคงรูปแบบโค้ดดั้งเดิมไว้ ผลลัพธ์การจัดรูปแบบจึงมีความไวต่อความยาวบรรทัดที่ระบุน้อยกว่าสีดำมาก

3. ใช้สีดำกับไอซอร์ท

ดังที่ฉันได้กล่าวไว้ก่อนหน้านี้ สีดำไม่ได้จัดเรียงการนำเข้าของคุณ และเราสามารถใช้isort (5.4k stars บน GitHub) เพื่อทำสิ่งนี้ได้ มาดูตัวอย่างรวดเร็วว่า isort ทำอะไรได้บ้าง:

มันเรียบร้อยและไม่ทำให้sys.path.appendตัวอย่าง ของเรายุ่งเหยิง

โปรดทราบว่ามีความแตกต่างเล็กน้อยระหว่างวิธีที่ isort และ black จัดระเบียบการนำเข้า และเราสามารถบอกให้ isort จัดเรียงการนำเข้าที่สอดคล้องกับสไตล์โค้ดสีisort --profile black format_06_raw.pyดำ

ตอนนี้เรามีเวิร์กโฟลว์ที่ค่อนข้างดี: ใช้ isort เพื่อจัดเรียงการนำเข้าก่อน จากนั้นใช้สีดำเพื่อจัดรูปแบบโค้ดของเรา เราสามารถรวมสองขั้นตอนเข้าด้วยกันใน Makefile:

format:
 isort --profile black src/
 black -l 100 src/

บทสรุป

ในบทความนี้ เราเปรียบเทียบเครื่องมือจัดรูปแบบอัตโนมัติยอดนิยมสองรายการใน Python — autopep8 และ black ฉันอธิบายว่าทำไมฉันถึงชอบสีดำและชอบใช้มันอย่างไร และฉันหวังว่านี่จะเป็นประโยชน์

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