Làm thế nào để tôi đề cập đến đối tượng null trong Python?
Làm thế nào để tôi đề cập đến đối tượng null trong Python?
Câu trả lời:
Trong Python, đối tượng 'null' là singleton None
.
Cách tốt nhất để kiểm tra mọi thứ cho "Tính không đồng nhất" là sử dụng toán tử nhận dạng , is
:
if foo is None:
...
None
, Python là null?Không có null
Python, thay vào đó là có None
. Như đã nêu, cách chính xác nhất để kiểm tra rằng một cái gì đó đã được đưa ra None
như một giá trị là sử dụng is
toán tử nhận dạng, để kiểm tra hai biến tham chiếu đến cùng một đối tượng.
>>> foo is None
True
>>> foo = 'bar'
>>> foo is None
False
None
None
là trường hợp duy nhất của lớp NoneType
và bất kỳ nỗ lực nào nữa trong việc khởi tạo lớp đó sẽ trả về cùng một đối tượng, điều này tạo ra None
một singleton. Những người mới sử dụng Python thường thấy các thông báo lỗi đề cập NoneType
và tự hỏi nó là gì. Theo ý kiến cá nhân của tôi, những tin nhắn này chỉ có thể được đề cập None
bằng tên bởi vì, như chúng ta sẽ thấy trong thời gian ngắn, None
để lại một khoảng trống nhỏ. Vì vậy, nếu bạn thấy một số TypeError
thông báo đề cập rằng NoneType
không thể làm điều này hoặc không thể làm điều đó, chỉ cần biết rằng đó đơn giản là một trong những thông điệp None
được sử dụng theo cách mà nó không thể.
Ngoài ra, None
là một hằng số tích hợp, ngay khi bạn khởi động Python, nó có sẵn để sử dụng từ mọi nơi, cho dù trong mô-đun, lớp hoặc chức năng. NoneType
ngược lại là không, trước tiên bạn cần có một tham chiếu đến nó bằng cách truy vấn None
lớp của nó.
>>> NoneType
NameError: name 'NoneType' is not defined
>>> type(None)
NoneType
Bạn có thể kiểm tra None
tính duy nhất với chức năng nhận dạng của Python id()
. Nó trả về số duy nhất được gán cho một đối tượng, mỗi đối tượng có một. Nếu id của hai biến là như nhau, thì thực tế chúng trỏ đến cùng một đối tượng.
>>> NoneType = type(None)
>>> id(None)
10748000
>>> my_none = NoneType()
>>> id(my_none)
10748000
>>> another_none = NoneType()
>>> id(another_none)
10748000
>>> def function_that_does_nothing(): pass
>>> return_value = function_that_does_nothing()
>>> id(return_value)
10748000
None
không thể ghi đèTrong phiên bản cũ hơn của Python (trước 2.4), có thể gán lại None
, nhưng không còn nữa. Thậm chí không phải là một thuộc tính lớp hoặc trong giới hạn của hàm.
# In Python 2.7
>>> class SomeClass(object):
... def my_fnc(self):
... self.None = 'foo'
SyntaxError: cannot assign to None
>>> def my_fnc():
None = 'foo'
SyntaxError: cannot assign to None
# In Python 3.5
>>> class SomeClass:
... def my_fnc(self):
... self.None = 'foo'
SyntaxError: invalid syntax
>>> def my_fnc():
None = 'foo'
SyntaxError: cannot assign to keyword
Do đó, an toàn khi cho rằng tất cả các None
tài liệu tham khảo đều giống nhau. Không có "tùy chỉnh" None
.
None
sử dụng is
toán tửKhi viết mã, bạn có thể muốn thử nghiệm tính Không giống như thế này:
if value==None:
pass
Hoặc để kiểm tra sự giả dối như thế này
if not value:
pass
Bạn cần hiểu ý nghĩa và lý do tại sao nó thường là một ý tưởng tốt để được rõ ràng.
None
tại sao làm điều này
value is None
thay vì
value==None
Đầu tiên là tương đương với:
id(value)==id(None)
Trong khi đó biểu thức value==None
trên thực tế được áp dụng như thế này
value.__eq__(None)
Nếu giá trị thực sự là None
thì bạn sẽ nhận được những gì bạn mong đợi.
>>> nothing = function_that_does_nothing()
>>> nothing.__eq__(None)
True
Trong hầu hết các trường hợp phổ biến, kết quả sẽ giống nhau, nhưng __eq__()
phương thức mở ra một cánh cửa không có bất kỳ sự đảm bảo nào về tính chính xác, vì nó có thể được ghi đè trong một lớp để cung cấp hành vi đặc biệt.
Hãy xem xét lớp học này.
>>> class Empty(object):
... def __eq__(self, other):
... return not other
Vì vậy, bạn hãy thử nó None
và nó hoạt động
>>> empty = Empty()
>>> empty==None
True
Nhưng sau đó nó cũng hoạt động trên chuỗi trống
>>> empty==''
True
Chưa hết
>>> ''==None
False
>>> empty is None
False
None
như một booleanHai bài kiểm tra sau
if value:
# do something
if not value:
# do something
trong thực tế được đánh giá là
if bool(value):
# do something
if not bool(value):
# do something
None
là một "falsey", có nghĩa là nếu được đúc thành boolean, nó sẽ quay trở lại False
và nếu được áp dụng not
toán tử, nó sẽ trả về True
. Lưu ý tuy nhiên đó không phải là một tài sản duy nhất None
. Ngoài ra False
, thuộc tính được chia sẻ bởi các danh sách trống, bộ dữ liệu, bộ, ký tự, chuỗi, cũng như 0 và tất cả các đối tượng từ các lớp thực hiện __bool__()
phương thức ma thuật để trả về False
.
>>> bool(None)
False
>>> not None
True
>>> bool([])
False
>>> not []
True
>>> class MyFalsey(object):
... def __bool__(self):
... return False
>>> f = MyFalsey()
>>> bool(f)
False
>>> not f
True
Vì vậy, khi kiểm tra các biến theo cách sau, hãy lưu ý thêm về những gì bạn bao gồm hoặc loại trừ khỏi kiểm tra:
def some_function(value=None):
if not value:
value = init_value()
Ở trên, bạn có nghĩa là gọi init_value()
khi giá trị được đặt cụ thể thành None
, hoặc bạn có nghĩa là một giá trị được đặt thành 0
, hoặc chuỗi trống hoặc danh sách trống cũng sẽ kích hoạt khởi tạo. Như tôi đã nói, hãy chú ý. Vì nó thường là trường hợp trong Python rõ ràng là tốt hơn ngầm định .
None
trong thực tếNone
được sử dụng làm giá trị tín hiệuNone
có một trạng thái đặc biệt trong Python. Đó là một giá trị cơ bản yêu thích vì nhiều thuật toán coi nó là một giá trị đặc biệt. Trong các trường hợp như vậy, nó có thể được sử dụng làm cờ để báo hiệu rằng một điều kiện yêu cầu một số xử lý đặc biệt (chẳng hạn như cài đặt giá trị mặc định).
Bạn có thể gán None
cho các đối số từ khóa của hàm và sau đó kiểm tra rõ ràng cho nó.
def my_function(value, param=None):
if param is None:
# do something outrageous!
Bạn có thể trả nó về mặc định khi cố gắng truy cập thuộc tính của đối tượng và sau đó kiểm tra rõ ràng trước khi thực hiện điều gì đó đặc biệt.
value = getattr(some_obj, 'some_attribute', None)
if value is None:
# do something spectacular!
Theo mặc định, get()
phương thức của từ điển trả về None
khi cố gắng truy cập khóa không tồn tại:
>>> some_dict = {}
>>> value = some_dict.get('foo')
>>> value is None
True
Nếu bạn cố gắng truy cập nó bằng cách sử dụng ký hiệu đăng ký KeyError
thì sẽ được nâng lên
>>> value = some_dict['foo']
KeyError: 'foo'
Tương tự như vậy nếu bạn cố gắng bật một mục không tồn tại
>>> value = some_dict.pop('foo')
KeyError: 'foo'
mà bạn có thể chặn với giá trị mặc định thường được đặt thành None
value = some_dict.pop('foo', None)
if value is None:
# booom!
None
được sử dụng làm cờ và giá trị hợp lệCác mô tả sử dụng ở trên được None
áp dụng khi nó không được coi là một giá trị hợp lệ, nhưng giống như một tín hiệu để làm điều gì đó đặc biệt. Tuy nhiên, có những tình huống đôi khi rất quan trọng để biết None
nguồn gốc từ đâu vì mặc dù nó được sử dụng như một tín hiệu, nó cũng có thể là một phần của dữ liệu.
Khi bạn truy vấn một đối tượng cho thuộc tính của nó với getattr(some_obj, 'attribute_name', None)
việc quay lại None
sẽ không cho bạn biết nếu thuộc tính bạn đang cố truy cập được đặt thành None
hoặc nếu nó hoàn toàn vắng mặt đối tượng. Tình trạng tương tự khi truy cập một khóa từ một từ điển như some_dict.get('some_key')
, bạn không biết nếu some_dict['some_key']
bị thiếu hoặc nếu nó chỉ được đặt thành None
. Nếu bạn cần thông tin đó, cách thông thường để xử lý việc này là trực tiếp thử truy cập thuộc tính hoặc khóa từ bên trong try/except
cấu trúc:
try:
# equivalent to getattr() without specifying a default
# value = getattr(some_obj, 'some_attribute')
value = some_obj.some_attribute
# now you handle `None` the data here
if value is None:
# do something here because the attribute was set to None
except AttributeError:
# we're now hanling the exceptional situation from here.
# We could assign None as a default value if required.
value = None
# In addition, since we now know that some_obj doesn't have the
# attribute 'some_attribute' we could do something about that.
log_something(some_obj)
Tương tự với dict:
try:
value = some_dict['some_key']
if value is None:
# do something here because 'some_key' is set to None
except KeyError:
# set a default
value = None
# and do something because 'some_key' was missing
# from the dict.
log_something(some_dict)
Hai ví dụ trên cho thấy cách xử lý các trường hợp đối tượng và từ điển, còn các chức năng thì sao? Điều tương tự, nhưng chúng tôi sử dụng đối số từ khóa dấu sao đôi cho đến cuối:
def my_function(**kwargs):
try:
value = kwargs['some_key']
if value is None:
# do something because 'some_key' is explicitly
# set to None
except KeyError:
# we assign the default
value = None
# and since it's not coming from the caller.
log_something('did not receive "some_key"')
None
chỉ được sử dụng như một giá trị hợp lệNếu bạn thấy rằng mã của bạn được đặt với try/except
mẫu ở trên chỉ đơn giản là để phân biệt giữa None
cờ và None
dữ liệu, thì chỉ cần sử dụng một giá trị thử nghiệm khác. Có một mẫu trong đó một giá trị nằm ngoài tập hợp các giá trị hợp lệ được chèn vào như một phần của dữ liệu trong cấu trúc dữ liệu và được sử dụng để kiểm soát và kiểm tra các điều kiện đặc biệt (ví dụ: ranh giới, trạng thái, v.v.). Một giá trị như vậy được gọi là sentinel và nó có thể được sử dụng theo cách None
được sử dụng làm tín hiệu. Việc tạo một sentinel trong Python là chuyện nhỏ.
undefined = object()
Đối undefined
tượng ở trên là duy nhất và không làm bất cứ điều gì có thể khiến chương trình quan tâm, do đó, đây là một sự thay thế tuyệt vời cho None
một lá cờ. Một số hãy cẩn thận áp dụng, thêm về điều đó sau khi mã.
Với chức năng
def my_function(value, param1=undefined, param2=undefined):
if param1 is undefined:
# we know nothing was passed to it, not even None
log_something('param1 was missing')
param1 = None
if param2 is undefined:
# we got nothing here either
log_something('param2 was missing')
param2 = None
Với chính tả
value = some_dict.get('some_key', undefined)
if value is None:
log_something("'some_key' was set to None")
if value is undefined:
# we know that the dict didn't have 'some_key'
log_something("'some_key' was not set at all")
value = None
Với một đối tượng
value = getattr(obj, 'some_attribute', undefined)
if value is None:
log_something("'obj.some_attribute' was set to None")
if value is undefined:
# we know that there's no obj.some_attribute
log_something("no 'some_attribute' set on obj")
value = None
Như tôi đã đề cập, các tùy chỉnh trước đó đi kèm với một số cảnh báo. Đầu tiên, chúng không phải là từ khóa như thế None
, nên python không bảo vệ chúng. Bạn có thể ghi đè lên phần undefined
trên của bạn bất cứ lúc nào, bất cứ nơi nào trong mô-đun được xác định, vì vậy hãy cẩn thận với cách bạn phơi bày và sử dụng chúng. Tiếp theo, thể hiện được trả về bởi object()
không phải là một singleton, nếu bạn thực hiện cuộc gọi đó 10 lần, bạn sẽ nhận được 10 đối tượng khác nhau. Cuối cùng, việc sử dụng một sentinel rất bình dị. Một sentinel dành riêng cho thư viện mà nó được sử dụng và vì vậy phạm vi của nó thường được giới hạn trong các phần bên trong của thư viện. Nó không nên "rò rỉ" ra ngoài. Mã bên ngoài chỉ nên biết về nó, nếu mục đích của chúng là mở rộng hoặc bổ sung API của thư viện.
Nó không được gọi là null như trong các ngôn ngữ khác, nhưng None
. Luôn luôn chỉ có một phiên bản của đối tượng này, vì vậy bạn có thể kiểm tra sự tương đương với x is None
(so sánh danh tính) thay vì x == None
, nếu bạn muốn.
None
. Sau đó, tất cả những người thông minh so sánh NoneType
sẽ chiến thắng!
Trong Python, để biểu thị sự vắng mặt của một giá trị, bạn có thể sử dụng giá trị Không có ( loại.NoneType.None ) cho các đối tượng và "" (hoặc len () == 0 ) cho chuỗi. Vì thế:
if yourObject is None: # if yourObject == None:
...
if yourString == "": # if yourString.len() == 0:
...
Về sự khác biệt giữa "==" và "là", kiểm tra nhận dạng đối tượng bằng cách sử dụng "==" là đủ. Tuy nhiên, vì hoạt động "is" được định nghĩa là hoạt động nhận dạng đối tượng, nên có thể sử dụng nó đúng hơn là "==". Không chắc chắn nếu có sự khác biệt về tốc độ.
Dù sao, bạn có thể có một cái nhìn tại:
0 == false
trả về true
là vì toán tử hai số bằng loại cưỡng chế. Tuy nhiên, với toán tử ba số bằng, 0 === false
trả về false
, vì 'số' và 'boolean' là các loại khác nhau.
true
trong điều kiện. Trong Rust và Go, 0
và false
là các loại khác nhau không thể so sánh cho sự bình đẳng.
Null là một loại đối tượng đặc biệt như:
>>>type(None)
<class 'NoneType'>
Bạn có thể kiểm tra xem một đối tượng có thuộc lớp 'noneType' không:
>>>variable = None
>>>variable is None
True
Thêm thông tin có sẵn tại Python Docs
Mỗi thử nghiệm giá trị thật , 'Không' kiểm tra trực tiếp như FALSE, vì vậy biểu thức đơn giản nhất là đủ:
if not foo:
True
cho bất kỳ giá trị giả nào, không chỉ None
.
egg is None
hơnegg == None
: Sau này có thể bị quá tải, và có khả năng phá vỡ khi so sánh đối tượng có giá trị với None (phụ thuộc vào cách nó được thực hiện, nhưng bạn không mong đợi tất cả mọi người để có comparisions với Không vào tài khoản, phải không?) , trong khiis
luôn hoạt động như nhau.