Tôi đã thấy một số ví dụ về mã như thế này:
if not someobj:
#do something
Nhưng tôi tự hỏi tại sao không làm:
if someobj == None:
#do something
Có sự khác biệt nào không? Có ai có lợi thế hơn người kia không?
X != None?
Tôi đã thấy một số ví dụ về mã như thế này:
if not someobj:
#do something
Nhưng tôi tự hỏi tại sao không làm:
if someobj == None:
#do something
Có sự khác biệt nào không? Có ai có lợi thế hơn người kia không?
X != None?
Câu trả lời:
Trong thử nghiệm đầu tiên, Python cố gắng chuyển đổi đối tượng thành một boolgiá trị nếu nó chưa phải là một giá trị. Một cách thô bạo, chúng tôi đang hỏi đối tượng: bạn có ý nghĩa hay không? Điều này được thực hiện bằng thuật toán sau:
Nếu đối tượng có một __nonzero__phương thức đặc biệt (cũng như tích hợp số intvà float), thì nó gọi phương thức này. Nó phải trả về một boolgiá trị được sử dụng trực tiếp hoặc intgiá trị được xem xét Falsenếu bằng 0.
Ngược lại, nếu các đối tượng có một __len__phương pháp đặc biệt (như làm thùng chứa được xây dựng-in, list, dict, set, tuple, ...), nó gọi phương pháp này, xem xét một container Falsenếu nó là rỗng (chiều dài là zero).
Mặt khác, đối tượng được xem xét Truetrừ khi nó nằm Nonetrong trường hợp nào, nó được xem xét False.
Trong thử nghiệm thứ hai, đối tượng được so sánh cho bằng None. Ở đây, chúng tôi đang hỏi đối tượng, "Bạn có bằng giá trị khác này không?" Điều này được thực hiện bằng thuật toán sau:
Nếu đối tượng có một __eq__phương pháp, nó được gọi, và giá trị trả về sau đó được chuyển thành một boolgiá trị và được sử dụng để xác định kết quả của if.
Ngược lại, nếu các đối tượng có một __cmp__phương pháp, nó được gọi. Hàm này phải trả về một intchỉ thị thứ tự của hai đối tượng ( -1if self < other, 0if self == other, +1if self > other).
Mặt khác, đối tượng được so sánh về danh tính (nghĩa là chúng được tham chiếu đến cùng một đối tượng, như có thể được kiểm tra bởi istoán tử).
Có một thử nghiệm khác có thể sử dụng istoán tử. Chúng tôi sẽ hỏi đối tượng, "Bạn có phải là đối tượng đặc biệt này không?"
Nói chung, tôi khuyên bạn nên sử dụng thử nghiệm đầu tiên với các giá trị không phải là số, để sử dụng thử nghiệm cho đẳng thức khi bạn muốn so sánh các đối tượng có cùng bản chất (hai chuỗi, hai số, ...) và chỉ kiểm tra nhận dạng khi sử dụng các giá trị sentinel ( Nonenghĩa là không được khởi tạo cho trường thành viên để lấy mẫu hoặc khi sử dụng getattrcác __getitem__phương thức hoặc ).
Để tóm tắt, chúng tôi có:
>>> 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
Đây thực sự là cả hai thực hành nghèo. Ngày xửa ngày xưa, việc coi ngẫu nhiên Không và Sai là tương tự nhau. Tuy nhiên, vì Python 2.2 nên đây không phải là chính sách tốt nhất.
Đầu tiên, khi bạn thực hiện một if xhoặc một if not xloại thử nghiệm, Python phải hoàn toàn chuyển đổi xsang boolean. Các quy tắc cho boolchức năng mô tả một bè của những thứ là Sai; mọi thứ khác đều đúng. Nếu giá trị của x không phải là boolean chính xác để bắt đầu, thì chuyển đổi ngầm định này thực sự không phải là cách rõ ràng nhất để nói.
Trước Python 2.2, không có hàm bool, vì vậy nó thậm chí còn chưa rõ ràng.
Thứ hai, bạn không nên thực sự thử nghiệm với == None. Bạn nên sử dụng is Nonevà is not None.
Xem PEP 8, Hướng dẫn kiểu cho mã Python .
- 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!
Có bao nhiêu singletons? Năm: None, True, False, NotImplementedvà Ellipsis. Vì bạn thực sự không thể sử dụng NotImplementedhoặc Ellipsis, và bạn sẽ không bao giờ nói if x is True(vì đơn giản if xlà rõ ràng hơn nhiều), bạn sẽ chỉ kiểm tra None.
Bởi vì Nonekhông phải là điều duy nhất được coi là sai.
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, (), [], {}Và ""tất cả đều khác nhau từ None, vì vậy hai đoạn mã của bạn là không tương đương.
Hơn nữa, hãy xem xét những điều sau đây:
>>> False == 0
True
>>> False == ()
False
if object:là không một kiểm tra bình đẳng. 0, (), [], None, {},, Vv là tất cả khác nhau từ mỗi khác, nhưng tất cả họ đều đánh giá là False.
Đây là "ma thuật" đằng sau các biểu thức ngắn mạch như:
foo = bar and spam or eggs
đó là viết tắt của:
if bar:
foo = spam
else:
foo = eggs
mặc dù bạn thực sự nên viết:
foo = spam if bar else egg
PEP 8 - Phong cách Hướng dẫn cho Python Mã khuyến cáo để sử dụng là hoặc không phải là nếu bạn đang thử nghiệm cho Không-Ness
- Comparisons to singletons like None should always be done with 'is' or 'is not', never the equality operators.
Mặt khác, nếu bạn đang kiểm tra nhiều hơn Không có, bạn nên sử dụng toán tử boolean.
Nếu bạn hỏi
if not spam:
print "Sorry. No SPAM."
các __nonzero__ phương pháp thư rác được gọi. Từ hướng dẫn Python:
__nonzero__ ( tự ) Được gọi để thực hiện kiểm tra giá trị thật và hoạt động tích hợp bool (); sẽ trả về Sai hoặc Đúng hoặc số nguyên tương đương của chúng 0 hoặc 1. Khi phương thức này không được xác định, __len __ () được gọi, nếu nó được xác định (xem bên dưới). Nếu một lớp định nghĩa không __len __ () hay __nonzero __ (), thì tất cả các thể hiện của nó được coi là đúng.
Nếu bạn hỏi
if spam == None:
print "Sorry. No SPAM here either."
các __eq__ phương pháp thư rác được gọi với đối số Không .
Để biết thêm thông tin về các khả năng tùy chỉnh, hãy xem thông tin về Python tại https://docs.python.org/reference/datamodel.html#basic-customization
Hai so sánh này phục vụ các mục đích khác nhau. Cái trước kiểm tra giá trị boolean của cái gì đó, cái thứ hai kiểm tra danh tính với giá trị Không có.
Câu trả lơi con phụ thuộc vao nhiêu thư".
Tôi sử dụng ví dụ đầu tiên nếu tôi coi 0, "", [] và Sai (danh sách không đầy đủ) tương đương với Không có trong ngữ cảnh này.
Cá nhân, tôi đã chọn một cách tiếp cận nhất quán giữa các ngôn ngữ: Tôi chỉ if (var)(hoặc tương đương) nếu var được khai báo là boolean (hoặc được định nghĩa như vậy, trong C chúng tôi không có một loại cụ thể). Tôi thậm chí còn thêm tiền tố vào các biến này bằng một b(vì vậy nó sẽ bVarthực sự) để chắc chắn rằng tôi sẽ không vô tình sử dụng một loại khác ở đây.
Tôi thực sự không thích truyền hình ngầm cho boolean, thậm chí ít hơn khi có nhiều quy tắc phức tạp.
Tất nhiên, mọi người sẽ không đồng ý. Một số đi xa hơn, tôi thấy if (bVar == true)trong mã Java trong công việc của tôi (quá dư thừa theo sở thích của tôi!), Những người khác yêu thích quá nhiều cú pháp nhỏ gọn, đi while (line = getNextLine())(quá mơ hồ đối với tôi).