ฉันเคยเห็นตัวอย่างของรหัสเช่นนี้:
if not someobj:
#do something
แต่ฉันสงสัยว่าทำไมไม่ทำ:
if someobj == None:
#do something
มีความแตกต่างหรือไม่? คนหนึ่งได้เปรียบกว่าอีกคนหนึ่งหรือเปล่า?
X != None?
ฉันเคยเห็นตัวอย่างของรหัสเช่นนี้:
if not someobj:
#do something
แต่ฉันสงสัยว่าทำไมไม่ทำ:
if someobj == None:
#do something
มีความแตกต่างหรือไม่? คนหนึ่งได้เปรียบกว่าอีกคนหนึ่งหรือเปล่า?
X != None?
คำตอบ:
ในการทดสอบครั้งแรก Python พยายามแปลงวัตถุให้เป็นboolค่าหากยังไม่ได้ทำการทดสอบ ประมาณเราจะขอวัตถุ: คุณมีความหมายหรือไม่? สิ่งนี้ทำได้โดยใช้อัลกอริทึมต่อไปนี้:
ถ้าวัตถุนั้นมี__nonzero__วิธีพิเศษ (เช่นเดียวกับในตัวตัวเลขintและfloat) มันเรียกวิธีนี้ โดยจะต้องส่งคืนboolค่าที่ใช้โดยตรงหรือintค่าที่พิจารณาFalseว่าเท่ากับศูนย์
มิฉะนั้นถ้าวัตถุที่มี__len__วิธีการพิเศษ (เช่นการทำภาชนะสร้างอินlist, dict, set, tuple, ... ) มันเรียกวิธีการนี้เมื่อพิจารณาจากภาชนะFalseถ้ามันเป็นที่ว่างเปล่า (ความยาวเป็นศูนย์)
มิฉะนั้นวัตถุถือว่าTrueเว้นแต่เป็นซึ่งในกรณีนี้ก็ถือว่าNoneFalse
Noneในการทดสอบที่สองวัตถุที่ถูกเมื่อเทียบเพื่อความเท่าเทียมกันในการ ที่นี่เราจะถามวัตถุ "คุณเท่ากับค่าอื่นนี้หรือไม่" สิ่งนี้ทำได้โดยใช้อัลกอริทึมต่อไปนี้:
ถ้าวัตถุมี__eq__วิธีการที่เรียกว่าและค่าตอบแทนจะถูกแปลงไปแล้วคุ้มค่าและใช้ในการกำหนดผลที่ได้จากboolif
มิฉะนั้นถ้าวัตถุนั้นมี__cmp__วิธีการก็จะถูกเรียกว่า ฟังก์ชั่นนี้จะต้องกลับintแสดงให้เห็นคำสั่งของสองวัตถุ ( -1ถ้าself < other, 0ถ้าself == other, +1ถ้าself > other)
มิฉะนั้นวัตถุจะถูกนำมาเปรียบเทียบเพื่อระบุตัวตน (เช่นพวกเขาจะอ้างอิงกับวัตถุเดียวกันที่สามารถทดสอบได้โดยisผู้ปฏิบัติงาน)
มีการทดสอบอื่นที่เป็นไปได้โดยใช้isโอเปอเรเตอร์ เราจะถามวัตถุ "คุณเป็นวัตถุเฉพาะหรือไม่"
โดยทั่วไปฉันขอแนะนำให้ใช้การทดสอบครั้งแรกกับค่าที่ไม่ใช่ตัวเลขเพื่อใช้การทดสอบเพื่อความเท่าเทียมกันเมื่อคุณต้องการเปรียบเทียบวัตถุที่มีลักษณะเดียวกัน (สองสาย, สองหมายเลข, ... ) และตรวจสอบตัวตนเฉพาะเมื่อ ใช้ค่า Sentinel ( Noneหมายถึงไม่ได้เริ่มต้นสำหรับเขตข้อมูลสมาชิกสำหรับตัวอย่างหรือเมื่อใช้getattrหรือ__getitem__วิธีการ)
เพื่อสรุปเรามี:
>>> class A(object):
... def __repr__(self):
... return 'A()'
... def __nonzero__(self):
... return False
>>> class B(object):
... def __repr__(self):
... return 'B()'
... def __len__(self):
... return 0
>>> class C(object):
... def __repr__(self):
... return 'C()'
... def __cmp__(self, other):
... return 0
>>> class D(object):
... def __repr__(self):
... return 'D()'
... def __eq__(self, other):
... return True
>>> for obj in ['', (), [], {}, 0, 0., A(), B(), C(), D(), None]:
... print '%4s: bool(obj) -> %5s, obj == None -> %5s, obj is None -> %5s' % \
... (repr(obj), bool(obj), obj == None, obj is None)
'': bool(obj) -> False, obj == None -> False, obj is None -> False
(): bool(obj) -> False, obj == None -> False, obj is None -> False
[]: bool(obj) -> False, obj == None -> False, obj is None -> False
{}: bool(obj) -> False, obj == None -> False, obj is None -> False
0: bool(obj) -> False, obj == None -> False, obj is None -> False
0.0: bool(obj) -> False, obj == None -> False, obj is None -> False
A(): bool(obj) -> False, obj == None -> False, obj is None -> False
B(): bool(obj) -> False, obj == None -> False, obj is None -> False
C(): bool(obj) -> True, obj == None -> True, obj is None -> False
D(): bool(obj) -> True, obj == None -> True, obj is None -> False
None: bool(obj) -> False, obj == None -> True, obj is None -> True
อันที่จริงแล้วทั้งสองวิธีปฏิบัติที่ไม่ดี กาลครั้งหนึ่งมันก็โอเคที่จะถือว่าไม่มีทางและไม่มีเท็จเหมือนกัน อย่างไรก็ตามเนื่องจาก Python 2.2 นี่ไม่ใช่นโยบายที่ดีที่สุด
ครั้งแรกเมื่อคุณทำการทดสอบif xหรือif not xชนิด Python จะต้องแปลงxเป็นบูลีนโดยปริยาย กฎสำหรับboolฟังก์ชั่นอธิบายแพของสิ่งต่าง ๆ ซึ่งเป็นเท็จ ทุกสิ่งทุกอย่างเป็นจริง หากค่าของ x ไม่บูลีนเริ่มต้นอย่างเหมาะสมการแปลงโดยนัยนี้ไม่ใช่วิธีที่ชัดเจนที่สุดในการพูดสิ่งต่าง ๆ
ก่อน Python 2.2 ไม่มีฟังก์ชั่นบูลจึงชัดเจนน้อยกว่า
== Noneประการที่สองคุณไม่ควรจริงๆทดสอบด้วย คุณควรใช้และis Noneis not None
ดู PEP 8 คู่มือสไตล์สำหรับงูหลามรหัส
- Comparisons to singletons like None should always be done with 'is' or 'is not', never the equality operators. Also, beware of writing "if x" when you really mean "if x is not None" -- e.g. when testing whether a variable or argument that defaults to None was set to some other value. The other value might have a type (such as a container) that could be false in a boolean context!
มีกี่ตันเดี่ยว? ห้า: None, True, False, และNotImplemented Ellipsisเนื่องจากคุณไม่น่าจะใช้จริง ๆNotImplementedหรือEllipsisและคุณจะไม่มีทางพูดif x is True(เพราะif xมีความชัดเจนมากขึ้น) คุณจะต้องทดสอบNoneเท่านั้น
เพราะNoneไม่ใช่สิ่งเดียวที่ถือว่าเป็นเท็จ
if not False:
print "False is false."
if not 0:
print "0 is false."
if not []:
print "An empty list is false."
if not ():
print "An empty tuple is false."
if not {}:
print "An empty dict is false."
if not "":
print "An empty string is false."
False, 0, (), [], {}และ""มีความแตกต่างกันทั้งหมดจากNoneดังนั้นโค้ดสองของคุณจะไม่เทียบเท่า
นอกจากนี้ให้พิจารณาสิ่งต่อไปนี้:
>>> False == 0
True
>>> False == ()
False
if object:คือไม่ได้ตรวจสอบความเท่าเทียมกัน 0, (), [], None, {}ฯลฯมีทั้งหมดแตกต่างจากคนอื่น ๆ แต่พวกเขาทั้งหมดประเมินการเท็จ
นี่คือ "เวทมนต์" ที่อยู่เบื้องหลังการแสดงออกทางลัดเช่น:
foo = bar and spam or eggs
ซึ่งจดชวเลขสำหรับ:
if bar:
foo = spam
else:
foo = eggs
แม้ว่าคุณควรเขียนจริง ๆ :
foo = spam if bar else egg
PEP ที่ 8 - คู่มือสไตล์สำหรับงูหลามรหัสแนะนำให้ใช้เป็นหรือไม่ถ้าคุณกำลังทดสอบไม่มี-Ness
- Comparisons to singletons like None should always be done with 'is' or 'is not', never the equality operators.
ในทางกลับกันหากคุณกำลังทดสอบมากกว่า None-ness คุณควรใช้โอเปอเรเตอร์บูลีน
หากคุณถาม
if not spam:
print "Sorry. No SPAM."
__nonzero__วิธีการสแปมได้รับเรียกว่า จากคู่มือ Python:
__nonzero__ ( ตัวเอง ) ถูกเรียกให้ทำการทดสอบค่าความจริงและบูลการดำเนินการในตัว (); ควรกลับเท็จหรือจริงหรือจำนวนเต็มเทียบเท่า 0 หรือ 1 เมื่อไม่ได้กำหนดวิธีนี้ __len __ () จะถูกเรียกถ้ามันถูกกำหนด (ดูด้านล่าง) หากคลาสไม่ได้กำหนด __len __ () หรือ __nonzero __ () คลาสทั้งหมดจะถือว่าเป็นจริง
หากคุณถาม
if spam == None:
print "Sorry. No SPAM here either."
__eq__วิธีการสแปมได้รับการเรียกว่ามีอาร์กิวเมนต์ไม่มี
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับความเป็นไปได้ในการปรับแต่งดูที่ Python documenation ที่https://docs.python.org/reference/datamodel.html#basic-customization
การเปรียบเทียบทั้งสองนี้มีวัตถุประสงค์ที่แตกต่างกัน อดีตตรวจสอบหาค่าบูลีนของบางอย่างที่สองตรวจสอบตัวตนด้วยไม่มีค่า
สำหรับตัวอย่างแรกนั้นสั้นกว่าและดูดีกว่า ตามโพสต์อื่น ๆ สิ่งที่คุณเลือกยังขึ้นอยู่กับสิ่งที่คุณต้องการจะทำกับการเปรียบเทียบ
คำตอบคือ "มันขึ้นอยู่กับ"
ฉันใช้ตัวอย่างแรกถ้าฉันพิจารณา 0, "", [] และเท็จ (รายการไม่ครบถ้วนสมบูรณ์) จะเทียบเท่ากับไม่มีในบริบทนี้
โดยส่วนตัวแล้วฉันเลือกวิธีที่สอดคล้องกันในหลายภาษา: ฉันทำif (var)(หรือเทียบเท่า) เฉพาะเมื่อ var ถูกประกาศว่าเป็นบูลีน (หรือกำหนดไว้เช่นนี้ใน C เราไม่มีประเภทเฉพาะ) ฉันยังนำหน้าตัวแปรเหล่านี้ด้วยb(ดังนั้นจึงเป็นbVarจริง) เพื่อให้แน่ใจว่าฉันจะไม่ใช้ชนิดอื่นที่นี่โดยไม่ตั้งใจ
ฉันไม่ชอบการชี้ขาดแบบบูลถึงแม้จะน้อยกว่าเมื่อมีกฎที่ซับซ้อนมากมาย
แน่นอนว่าคนจะไม่เห็นด้วย บางคนไปไกลกว่าฉันเห็นif (bVar == true)ในโค้ด Java ที่งานของฉัน (ซ้ำซ้อนเกินไปสำหรับรสนิยมของฉัน!) คนอื่น ๆ ชอบไวยากรณ์ขนาดกะทัดรัดมากเกินไปไปwhile (line = getNextLine())(คลุมเครือเกินไปสำหรับฉัน)