Python รองรับการลัดวงจรหรือไม่?


คำตอบ:



192

พฤติกรรมการลัดวงจรในผู้ประกอบการand, or:

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

>>> def fun(i):
...     print "executed"
...     return i
... 

หนึ่งสามารถสังเกตพฤติกรรมการลัดวงจร- ธของand, orผู้ประกอบการในตัวอย่างต่อไปนี้:

>>> fun(1)
executed
1
>>> 1 or fun(1)    # due to short-circuiting  "executed" not printed
1
>>> 1 and fun(1)   # fun(1) called and "executed" printed 
executed
1
>>> 0 and fun(1)   # due to short-circuiting  "executed" not printed 
0

หมายเหตุ:ค่าต่อไปนี้ถูกพิจารณาโดยล่ามเพื่อหมายถึงเท็จ:

        False    None    0    ""    ()    []     {}

พฤติกรรมการลัดวงจรในฟังก์ชัน: any(), all():

งูหลามany()และall()ฟังก์ชั่นยังรองรับการลัดวงจร ตามที่แสดงในเอกสาร; พวกเขาประเมินแต่ละองค์ประกอบของลำดับตามลำดับจนกระทั่งพบผลลัพธ์ที่อนุญาตให้ออกก่อนกำหนดในการประเมินผล พิจารณาตัวอย่างด้านล่างเพื่อทำความเข้าใจทั้งสองอย่าง

ฟังก์ชั่นany()ตรวจสอบว่าองค์ประกอบใด ๆ เป็นจริง มันจะหยุดดำเนินการทันทีที่พบ True และส่งคืน True

>>> any(fun(i) for i in [1, 2, 3, 4])   # bool(1) = True
executed
True
>>> any(fun(i) for i in [0, 2, 3, 4])   
executed                               # bool(0) = False
executed                               # bool(2) = True
True
>>> any(fun(i) for i in [0, 0, 3, 4])
executed
executed
executed
True

ฟังก์ชั่นall()ตรวจสอบองค์ประกอบทั้งหมดเป็นจริงและหยุดดำเนินการทันทีที่พบเท็จ:

>>> all(fun(i) for i in [0, 0, 3, 4])
executed
False
>>> all(fun(i) for i in [1, 0, 3, 4])
executed
executed
False

พฤติกรรมการลัดวงจรในการเปรียบเทียบแบบล่ามโซ่:

นอกจากนี้ใน Python

การเปรียบเทียบสามารถถูกล่ามโซ่โดยพลการ ; ตัวอย่างเช่นx < y <= zเทียบเท่าx < y and y <= zยกเว้นที่yประเมินเพียงครั้งเดียว (แต่ในทั้งสองกรณีzไม่ได้รับการประเมินเลยเมื่อx < yพบว่าเป็นเท็จ)

>>> 5 > 6 > fun(3)    # same as:  5 > 6 and 6 > fun(3)
False                 # 5 > 6 is False so fun() not called and "executed" NOT printed
>>> 5 < 6 > fun(3)    # 5 < 6 is True 
executed              # fun(3) called and "executed" printed
True
>>> 4 <= 6 > fun(7)   # 4 <= 6 is True  
executed              # fun(3) called and "executed" printed
False
>>> 5 < fun(6) < 3    # only prints "executed" once
executed
False
>>> 5 < fun(6) and fun(6) < 3 # prints "executed" twice, because the second part executes it again
executed
executed
False

แก้ไข:
จุดหนึ่งที่น่าสนใจมากขึ้นที่จะต้องทราบ: -ตรรกะand,orผู้ประกอบการในหลามผลตอบแทนของตัวถูกดำเนินการค่าแทนการบูลีน ( TrueหรือFalse) ตัวอย่างเช่น:

การดำเนินการx and yให้ผลลัพธ์if x is false, then x, else y

ซึ่งแตกต่างจากในภาษาอื่น ๆ เช่น&&, ||ผู้ประกอบการในซีที่ผลตอบแทน 0 หรือ 1

ตัวอย่าง:

>>> 3 and 5    # Second operand evaluated and returned 
5                   
>>> 3  and ()
()
>>> () and 5   # Second operand NOT evaluated as first operand () is  false
()             # so first operand returned 

orผู้ประกอบการในทำนองเดียวกันกลับเหลือค่ามากที่สุดซึ่งbool(value)==Trueอื่นที่เหมาะสมมูลค่าเท็จมากที่สุด (ตามพฤติกรรมการลัดวงจร) ตัวอย่าง:

>>> 2 or 5    # left most operand bool(2) == True
2    
>>> 0 or 5    # bool(0) == False and bool(5) == True
5
>>> 0 or ()
()

ดังนั้นสิ่งนี้มีประโยชน์อย่างไร? หนึ่งใช้ตัวอย่างที่ได้รับในการปฏิบัติหลามโดยแมกนัสโกหก Hetland:
สมมติว่าผู้ใช้ควรจะใส่ชื่อของเขาหรือเธอ '<unknown>'แต่อาจเลือกที่จะใส่อะไรซึ่งในกรณีที่คุณต้องการใช้ค่าเริ่มต้น คุณสามารถใช้คำสั่ง if แต่คุณยังสามารถระบุสิ่งที่รัดกุมมาก:

In [171]: name = raw_input('Enter Name: ') or '<Unkown>'
Enter Name: 

In [172]: name
Out[172]: '<Unkown>'

กล่าวอีกนัยหนึ่งถ้าค่าส่งคืนจาก raw_input เป็นจริง (ไม่ใช่สตริงว่าง) จะถูกกำหนดเป็นชื่อ (ไม่มีการเปลี่ยนแปลง) มิฉะนั้นเริ่มต้นได้รับมอบหมายให้'<unknown>'name


1
การเล่นโวหารเล็กน้อย: รายการที่ชัดเจนของค่าที่ผิดพลาดจะทำให้เข้าใจผิดเล็กน้อย ประเภทใดก็ได้สามารถมีค่าที่ผิดพลาดอย่างน้อยหนึ่งค่า โดยการประชุมทุกประเภทที่เป็นตัวเลขที่มีค่า0เป็น falsy (ดังนั้นจึงไม่ได้เป็นเพียง0ก็0.0, 0j, decimal.Decimal(0), fractions.Fraction(0)ฯลฯ ) เช่นเดียวกับคอลเลกชันทั้งหมดที่มีความยาว0(เพื่อให้อยู่ด้านบนของสิ่งที่คุณอยู่ในรายการb''[Py3] u''[Py2] และset()/ frozenset()มี บิวด์อินทั้งหมดที่ประเมินว่าเป็นเท็จ) แต่ผู้ใช้กำหนดเอง / บุคคลที่สามสามารถกำหนดประเภทของตนเอง (ด้วย__bool__[Py3] / __nonzero__[Py2] โดยตรงหรือโดยอ้อมโดยการกำหนด__len__)
ShadowRanger

@ShadowRanger ที่นี่ความคิดเห็นของคุณจะทำให้คำตอบของฉันสมบูรณ์ ขอบคุณที่เพิ่มบันทึกนี้
Grijesh Chauhan

นอกจากนี้ไพ ธ อนจะประเมินเงื่อนไขที่มีการลัดวงจรสองครั้งหากใช้ในภายหลังเป็นบูลีน ... เว้นแต่ว่าพวกเขาจะอยู่ในข้อความสั่ง if ซึ่งได้รับสิทธิ์
Erik Aronesty

48

ใช่. ลองต่อไปนี้ในตัวแปลของหลาม:

และ

>>>False and 3/0
False
>>>True and 3/0
ZeroDivisionError: integer division or modulo by zero

หรือ

>>>True or 3/0
True
>>>False or 3/0
ZeroDivisionError: integer division or modulo by zero
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.