ใน Python ฉันควรทดสอบว่าตัวแปรเป็น None, True หรือ False


147

ฉันมีฟังก์ชั่นที่สามารถคืนหนึ่งในสามสิ่ง:

  • สำเร็จ ( True)
  • ความล้มเหลว ( False)
  • ข้อผิดพลาดในการอ่าน / การแยกสตรีม ( None)

คำถามของฉันคือถ้าฉันไม่ควรทดสอบTrueหรือFalseฉันจะดูได้อย่างไรว่าผลลัพธ์คืออะไร ด้านล่างเป็นวิธีที่ฉันทำอยู่ในปัจจุบัน:

result = simulate(open("myfile"))
if result == None:
    print "error parsing stream"
elif result == True: # shouldn't do this
    print "result pass"
else:
    print "result fail"

มันง่ายพอ ๆ กับการถอดชิ้น== Trueส่วนออกหรือว่าฉันควรจะเพิ่ม tri-bool data-type ฉันไม่ต้องการให้simulateฟังก์ชันโยนข้อยกเว้นเนื่องจากฉันต้องการให้โปรแกรมภายนอกทำโดยมีข้อผิดพลาดคือบันทึกและดำเนินการต่อ


คุณกำลังถามคำถามผิด คุณควรจะขอความช่วยเหลือเพื่อกำหนดผลลัพธ์ของคุณ ... อะไรคือความแตกต่างที่คุณรับรู้ระหว่าง "ความล้มเหลว" และ "ข้อผิดพลาดในการแยกวิเคราะห์กระแส" สิ่งที่พวกเขาหมายถึงอะไรผลที่ตามมาคืออะไร ในแต่ละกรณี (ผ่าน, ล้มเหลว, ข้อผิดพลาดในการแยกวิเคราะห์)?
John Machin

ฉันกำลังจำลองระบบไฟฟ้าถ้าผู้คนสูญเสียพลังงานไปที่บ้านของพวกเขามันเป็นความล้มเหลว หากฉันไม่สามารถอ่านไฟล์จำลองได้นั่นเป็นข้อผิดพลาดที่แตกต่างไปจากเดิมอย่างสิ้นเชิง
James Brooks

2
ภายในsimulateฟังก์ชั่นฉันจับทุกข้อยกเว้น; ฉันไม่ต้องการให้สิ่งใดที่เกิดขึ้นภายในเครื่องจำลองหยุดการทำงานของโปรแกรมที่เหลือ (และประมวลผลองค์ประกอบถัดไป) แต่คำตอบนั้นทำให้ฉันเปลี่ยนใจ
James Brooks

1
@ James Brooks: ถูกต้อง นั่นคือสิ่งที่ลอง / ยกเว้นการประมวลผลเป็นเรื่องเกี่ยวกับ หากคุณsimulateมีสิ่งที่สามารถจับและลองใหม่ได้ดี แต่ถ้ามันว่า "ล้มเหลว" Noneก็ไม่ควรกลับมา มันควรเพิ่มข้อยกเว้นให้กับสคริปต์ที่เรียกมันว่า ไม่ว่าจะด้วยวิธีใดsimulateก็ตาม การกลับมาNoneไม่ได้มีประโยชน์เท่ากับการสร้างข้อยกเว้นที่เหมาะสม - หรืออนุญาตให้มีข้อยกเว้นเพื่อเผยแพร่ผ่านsimulateไปยังสคริปต์การโทรสำหรับการจัดการ
S.Lott

1
@ James ใช้except Exception:แทน นี้จับความผิดพลาด "ของจริง" พร้อมด้วยและWarning StopIterationมันช่วยให้KeyboardInterruptและSystemExitผ่านแม้ว่า หากคุณต้องการจับสิ่งเหล่านั้นจริง ๆ ก็น่าจะดีที่สุดที่จะใช้ตัวอื่นลองนอก / ยกเว้นหรือโครงสร้างอื่น ๆ ที่แสดงถึงเจตนาของคุณอย่างชัดเจนเนื่องจากสิ่งเหล่านั้นไม่ใช่ "ข้อผิดพลาด" ( แต่ผมไม่ได้พูดว่า "เกือบจะไม่" ... บางทีอาจจะเป็นในกรณีของคุณจริงๆคุณต้องการที่จะคว้าทุกอย่างและยังป้องกันไม่ให้ Ctrl-C หรือsys.exit()การออกจาก ฯลฯ )
ปีเตอร์แฮนเซน

คำตอบ:


119

อย่ากลัวข้อยกเว้น! มีโปรแกรมของคุณเพียงเข้าสู่ระบบและดำเนินการต่อเป็นเรื่องง่ายเหมือน:

try:
    result = simulate(open("myfile"))
except SimulationException as sim_exc:
    print "error parsing stream", sim_exc
else:
    if result:
        print "result pass"
    else:
        print "result fail"

# execution continues from here, regardless of exception or not

และตอนนี้คุณสามารถมีการแจ้งเตือนที่หลากหลายยิ่งขึ้นจากวิธีการจำลองเป็นสิ่งที่ผิดพลาดอย่างแน่นอนในกรณีที่คุณพบข้อผิดพลาด / ไม่มีข้อผิดพลาดไม่ให้ข้อมูลเพียงพอ


ตกลง ไพทอนนิกมากกว่าสารละลายที่ได้รับความนิยมอย่างเห็นได้ชัดด้านบน (ซึ่งมีกลิ่นเหมือนรหัส C มากเกินไป)
Brandon

7
@Brandon ไม่เห็นด้วย รหัสนี้มีความยาวมากกว่าและแย่กว่าอ่านได้น้อยกว่าโซลูชันด้านบน (หรือรุ่นที่ปรับปรุงด้านล่าง): การเยื้องมากขึ้นข้อความที่แตกต่างกันมากขึ้น - เดาว่าทำไมบทหลังจึงเป็นที่นิยมมากกว่าในขณะที่คุณพูดว่า ... ;-) 'Pythonic' ถ้ามันนำไปสู่รหัสที่น่าอึดอัดใจมากขึ้น ... ?
Rolf Bartstra

ตอนนี้พิมพ์ traceback แทน "การแยกวิเคราะห์ข้อผิดพลาด" และคุณได้รับการโหวตของฉัน
CivFan

ตกลงคุณมีคะแนนของฉันอยู่แล้ว traceback.format_exc() แต่ผมหมายถึงบางสิ่งบางอย่างเช่นการพิมพ์ ดูคำตอบ SO นี้
CivFan

12
หลายคนจะมาที่หน้านี้เพื่อค้นหาคำตอบของคำถามชื่อ สำหรับพวกเราส่วนใหญ่ "อย่ากลัวข้อยกเว้น!" ไม่มีอะไรเกี่ยวข้องกับสถานการณ์ของเรา เราแค่ต้องทดสอบหาจริงเท็จและไม่มี ในขณะที่ทางเลือกที่คุณแนะนำนั้นถูกต้องสำหรับบางกรณีฉันคิดว่าวิธีที่ดีที่สุดคือให้รวมคำตอบของคำถามตามที่ถาม
vastlysuperiorman

163
if result is None:
    print "error parsing stream"
elif result:
    print "result pass"
else:
    print "result fail"

ทำให้มันง่ายและชัดเจน แน่นอนคุณสามารถกำหนดพจนานุกรมล่วงหน้าได้

messages = {None: 'error', True: 'pass', False: 'fail'}
print messages[result]

หากคุณวางแผนที่จะแก้ไขsimulateฟังก์ชั่นของคุณให้ใส่รหัสที่ส่งคืนมากขึ้นการรักษารหัสนี้อาจกลายเป็นปัญหาเล็กน้อย

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


1
สิ่งหลังคือการทดสอบที่ชัดเจนต่อ True หรือเท็จใช่ไหม
Peter Eisentraut

1
แน่นอน แต่การรู้ว่าสิ่งเหล่านี้เป็นเพียงค่าตอบแทนที่เป็นไปได้ฉันไม่คิดว่ามันจะเป็นปัญหา
SilentGhost

และดูเหมือนว่าจะเร็วขึ้นอีกเล็กน้อยเช่นกัน
SilentGhost

a = 'foo' ถ้า a: พิมพ์ 'มันจริง' a ไม่ใช่จริงจริงมันไม่ใช่ไม่ใช่เลย
wesm

17

ไม่เคยไม่เคยไม่เคยพูด

if something == True:

ไม่เคย มันบ้าเพราะคุณซ้ำซ้อนซ้ำสิ่งที่ระบุซ้ำซ้อนเป็นกฎเงื่อนไขซ้ำซ้อนสำหรับคำสั่ง if

แย่ลงยังไม่เคยไม่เคยไม่เคยพูด

if something == False:

notคุณมี รู้สึกอิสระที่จะใช้มัน

ในที่สุดการทำa == Noneไม่มีประสิทธิภาพ a is NoneDo Noneเป็นวัตถุแบบซิงเกิลพิเศษสามารถมีได้เพียงวัตถุเดียว เพียงตรวจสอบเพื่อดูว่าคุณมีวัตถุนั้น


3
การทดสอบเพื่อความเท่าเทียมกับTrueไม่ซ้ำซ้อน (แม้ว่าฉันเห็นด้วยว่ามันไม่สมเหตุสมผล) มันอาจจะเรียก__eq__วิธีการพิเศษหรืออื่น ๆ ซึ่งสามารถทำอะไรได้จริง
Scott Griffiths

5
@Scott Griffiths: ดีมาก นั่นเป็นสถานการณ์ที่น่ากลัวอย่างแท้จริงและลึกซึ้ง หากเป็นกรณีนี้โปรแกรมละเมิดความคาดหวังขั้นพื้นฐานของเราในวิธีการที่ทำให้บางสิ่งบางอย่างที่จำเป็นต้องถูกลบและเขียนใหม่โดยไม่ต้องมีเวทมนตร์ดำ
S.Lott

78
'ไม่ไม่ไม่เคยไม่เคย' ... ? มีหลายกรณีว่าที่if something == Trueอัตราผลตอบแทนผลที่แตกต่างกันมากกว่าเช่นการที่ไม่ใช่แบบบูลif something ให้ผลเป็นเท็จในขณะที่ประเมินเป็นจริง เป็นเท็จ แต่จริง! something2==True2None==Falsenot None
Rolf Bartstra

9
-1 คำตอบนี้ทำให้เข้าใจผิดและไม่ถูกต้องอย่างสมบูรณ์เนื่องจากสิ่งที่ @Rolf Bartstra พูดว่าเป็นความจริง แม้ว่าในกรณีนี้สิ่งที่คุณพูดสามารถนำไปใช้
HelloGoodbye

3
-1 ตั้งแต่ใด ๆ ค่าที่ไม่ใช่ศูนย์หรือไม่ว่างเปล่าหรือไม่ความยาวเป็นศูนย์สำหรับsomethingผลตอบแทนในTrue bool(something)ในกรณีที่ถ้าคุณเพียงต้องการที่จะตรวจสอบว่าsomethingมีค่าเช่นTrue boolจากนั้นคุณต้องทำif something == TrueIMO
Samarth Shah

2

ผมอยากจะเน้นว่าแม้ว่ามีสถานการณ์ที่if expr :ไม่เพียงพอเพราะใครอยากที่จะให้แน่ใจว่าexprเป็นTrueและไม่เพียง แต่แตกต่างจาก0/ None/ สิ่งที่isจะได้รับการที่ต้องการจาก== เหตุผลเดียวกัน S.Lott mentionned == Noneสำหรับการหลีกเลี่ยง

มันมีประสิทธิภาพมากขึ้นเล็กน้อยและเชอร์รี่บนเค้กอ่านง่ายขึ้น

In [1]: %timeit (1 == 1) == True
38.1 ns ± 0.116 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [2]: %timeit (1 == 1) is True
33.7 ns ± 0.141 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

1
คุณไม่สามารถรันเกณฑ์มาตรฐานหนึ่งครั้งและบอกว่ามีประสิทธิภาพมากกว่าอีกมาตรฐานหนึ่ง (แม้ว่าอาจจะเป็น) เรียกใช้หลาย ๆ ครั้ง (10.000) เพื่อดูว่ามันทำงานอย่างไรโดยเฉลี่ย \
user1767754

1

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

result = simulate(open("myfile"))
if not result[0]:
  print "error parsing stream"
else:
  ret= result[1]

1
กลับ tuple มักจะไปได้ดีกับการเปิดออกอันดับหนึ่ง)
SilentGhost

2
อย่างไรก็ตามรหัสของคุณไม่สมเหตุสมผลหากFalseถูกส่งคืนรหัสนั้นจะพิมพ์ออก'error parsing stream'มา
SilentGhost

วิธีการจำลองควรคืนค่า (เท็จ, "อะไรก็ได้เลย") หรือ (True, ret) โดยที่ ret เป็นเท็จหรือจริง
kgiannakakis

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