หลามยืนยันโดยมีและไม่มีวงเล็บ


105

ต่อไปนี้คือคำเรียกร้องง่ายๆสี่ข้อของการยืนยัน:

>>> assert 1==2
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AssertionError

>>> assert 1==2, "hi"
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AssertionError: hi

>>> assert(1==2)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AssertionError

>>> assert(1==2, "hi")

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


ขอบคุณสำหรับคำตอบที่เป็นประโยชน์ ความแตกต่างระหว่างคีย์เวิร์ดและฟังก์ชันในตัวดูเหมือนละเอียดอ่อน นี่คือรายการคำหลักที่ฉันคิดว่าควรทิ้ง parens ไว้: docs.python.org/reference/lexical_analysis.html#keywords
gaefan

2
ความแตกต่างอย่างหนึ่งคือคุณสามารถกำหนดฟังก์ชันในตัวใหม่ได้ แต่ไม่สามารถทำได้ด้วยคีย์เวิร์ด (ไม่ใช่ว่าเดิมเป็นความคิดที่ดี)
gaefan

มันไม่ได้เป็นฟังก์ชั่นเทียบกับความแตกต่างของคำหลัก แต่การเรียกใช้ฟังก์ชันเทียบกับคำสั่ง (ตัวอย่างเช่น - พิมพ์เคยเป็นคำสั่งและทำงานโดยไม่มีวงเล็บ)
Tomasz Gandor

คำตอบ:


130

ข้อสุดท้ายassertจะให้คำเตือนคุณ ( SyntaxWarning: assertion is always true, perhaps remove parentheses?) หากคุณใช้งานผ่านล่ามเต็มรูปแบบไม่ใช่ผ่าน IDLE เนื่องจากassertเป็นคีย์เวิร์ดไม่ใช่ฟังก์ชันคุณกำลังส่งทูเพิลเป็นอาร์กิวเมนต์แรกและออกจากอาร์กิวเมนต์ที่สอง

จำได้ว่า tuples ไม่ว่างเปล่าประเมินTrueและตั้งแต่ข้อความยืนยันเป็นตัวเลือกที่คุณเรียกว่าเป็นหลักเมื่อคุณเขียนassert Trueassert(1==2, "hi")


10
เหตุผลไม่ได้เกิดขึ้นเพราะassert (1==2)วงเล็บรอบนิพจน์เดียวจะไม่สร้างทูเพิลโดยอัตโนมัติ คุณจะได้รับพฤติกรรมเช่นเดียวกับ # 4 assert (1==2,)ถ้าคุณไม่ได้ทำ สิ่งเดียวกันจะเกิดขึ้นถ้าคุณทำprint ('foo', 'bar')แทนprint 'foo', 'bar'; คุณจะเห็นทูเปิลที่ถูกลบออก
Michael Mrozek

ควรเน้นเพิ่มเติมว่าข้อความในแบบฟอร์มassert(test, message)อาจผิดและสับสนอย่างแน่นอน ไม่มี parens!
tcarobruce

19
ดังนั้นวิธีที่เหมาะสมในการเยื้องข้อความยืนยันแบบยาว wrt PEP8 คืออะไร? ดูเหมือนจะเป็นไปไม่ได้
stantonk


30

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

foo = 7
assert foo == 8, \
    "derp should be 8, it is " + str(foo)

พิมพ์:

AssertionError: "derp should be 8, it is 7

เหตุใดงูเหลือมตัวนี้assertจึงต้องแตกต่างจากสิ่งอื่น ๆ :

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

ฉันแบ่งปันความรำคาญของคุณที่ python assertมีไวยากรณ์ที่ไม่ซ้ำกันเมื่อเทียบกับโครงสร้างการเขียนโปรแกรม python อื่น ๆ และไวยากรณ์นี้ยังเปลี่ยนจาก python2 เป็น python3 อีกครั้งและเปลี่ยนอีกครั้งจาก python 3.4 เป็น 3.6 การยืนยันคำสั่งไม่สามารถใช้งานร่วมกันได้กับเวอร์ชันอื่น ๆ

มันคือการแตะที่ไหล่ซึ่งassertเป็นพลเมืองชั้น 3 มันจะถูกลบออกทั้งหมดใน python4 และอีกครั้งใน Python 8.1


2
มีเอกสารเกี่ยวกับสิ่งที่เราควรใช้แทนการยืนยันหรือไม่? Assert ดูเหมือนชื่อตรรกะสำหรับการตรวจสอบความถูกต้องและมีลักษณะการทำงานที่ต้องการเช่นแสดงข้อความพิเศษเมื่อเกิดข้อผิดพลาด
AnneTheAgile

18

assert 1==2, "hi"จะถูกแยกวิเคราะห์เช่นเดียวassert 1==2, "hi"กับ "hi" เป็นพารามิเตอร์ที่สองสำหรับคำหลัก เหตุใดจึงให้ข้อผิดพลาดอย่างถูกต้อง

assert(1==2)จะแยกเป็นassert (1==2)ซึ่งเป็นเหมือนassert 1==2เพราะ parens รอบรายการเดียวไม่ได้สร้าง tuple (1==2,)เว้นแต่มีต่อท้ายเช่นจุลภาค

assert(1==2, "hi")ถูกแยกวิเคราะห์เป็นassert (1==2, "hi")ซึ่งไม่ให้ข้อผิดพลาดเนื่องจากทูเปิลที่(False, "hi")ไม่ว่างเปล่าไม่ใช่ค่าเท็จและไม่มีพารามิเตอร์ที่สองที่ระบุให้กับคีย์เวิร์ด

คุณไม่ควรใช้วงเล็บเพราะassertไม่ใช่ฟังก์ชันใน Python แต่เป็นคีย์เวิร์ด


14

คุณสามารถทำลายคำสั่งยืนยันได้โดยไม่ต้องทำ\เช่นนี้:

foo = 7
assert foo == 8, (
    'derp should be 8, it is ' + str(foo))

หรือหากคุณมีข้อความที่ยาวกว่านี้:

foo = 7
assert foo == 8, (
    'Lorem Ipsum is simply dummy text of the printing and typesetting '
    'industry. Lorem Ipsum has been the industry\'s standard dummy text '
    'ever since the 1500s'
)

1
ความคิดที่น่าสนใจ ฉันเกลียดแบ็กสแลชสำหรับความต่อเนื่องและนี่เป็นอีกทางเลือกหนึ่งในการตัดการยืนยันในฟังก์ชันยูทิลิตี้ (ซึ่งเป็นวิธีแก้ปัญหาของฉัน)
Tomasz Gandor

1

ต่อไปนี้อ้างจากpython doc

คำสั่ง Assert เป็นวิธีที่สะดวกในการแทรกการยืนยันการแก้จุดบกพร่องลงในโปรแกรม:

assert_stmt ::= "assert" expression ["," expression]

รูปแบบที่เรียบง่ายการแสดงออกที่แสดงออกเทียบเท่ากับ if __debug__: if not expression: raise AssertionError

รูปแบบขยาย assert expression1, expression2เทียบเท่ากับ if __debug__: if not expression1: raise AssertionError(expression2)

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.