ฉันจะอ้างถึงวัตถุ null ใน Python ได้อย่างไร
ฉันจะอ้างถึงวัตถุ null ใน Python ได้อย่างไร
คำตอบ:
ใน Python วัตถุ 'null' คือ singleton None
วัตถุเดี่ยว
วิธีที่ดีที่สุดในการตรวจสอบสิ่งต่าง ๆ สำหรับ "Noneness" คือการใช้ตัวดำเนินการระบุตัวตนis
:
if foo is None:
...
None
, Python ว่างเปล่า?ไม่มีในหลามแทนที่จะมีnull
None
ตามที่ระบุไว้แล้ววิธีที่ถูกต้องที่สุดในการทดสอบว่าสิ่งที่ได้รับNone
เป็นค่าคือการใช้is
ตัวดำเนินการประจำตัวซึ่งทดสอบว่าตัวแปรสองตัวอ้างถึงวัตถุเดียวกัน
>>> foo is None
True
>>> foo = 'bar'
>>> foo is None
False
None
None
เป็นอินสแตนซ์เดียวของคลาสNoneType
และความพยายามเพิ่มเติมใด ๆ ในการสร้างอินสแตนซ์ของคลาสนั้นจะส่งคืนออบเจ็กต์เดียวกันซึ่งทำให้None
เกิดซิงเกิลตัน ผู้มาใหม่สู่ Python มักจะเห็นข้อความแสดงข้อผิดพลาดที่กล่าวถึงNoneType
และสงสัยว่ามันคืออะไร มันเป็นความคิดเห็นส่วนตัวของฉันว่าข้อความเหล่านี้สามารถพูดถึงNone
ชื่อเพราะอย่างที่เราจะเห็นในไม่ช้าNone
ทำให้ห้องเล็ก ๆ คลุมเครือ ดังนั้นหากคุณเห็นTypeError
ข้อความที่ระบุว่าNoneType
ไม่สามารถทำได้หรือไม่สามารถทำได้ให้รู้ว่าเป็นเพียงข้อความNone
ที่ถูกใช้ในวิธีที่ไม่สามารถทำได้
นอกจากนี้ยังNone
เป็นค่าคงที่ในตัวทันทีที่คุณเริ่ม Python พร้อมใช้งานจากทุกที่ไม่ว่าจะเป็นโมดูลคลาสหรือฟังก์ชัน NoneType
ในทางตรงกันข้ามไม่ได้คุณจะต้องได้รับการอ้างอิงถึงมันก่อนโดยการสอบถามNone
ระดับของมัน
>>> NoneType
NameError: name 'NoneType' is not defined
>>> type(None)
NoneType
คุณสามารถตรวจสอบNone
's id()
เอกลักษณ์ที่มีฟังก์ชั่นตัวตนของงูใหญ่ มันจะส่งกลับจำนวนที่ไม่ซ้ำกันที่กำหนดให้กับวัตถุแต่ละวัตถุมีหนึ่ง หากรหัสของสองตัวแปรเหมือนกันดังนั้นพวกเขาชี้ไปที่วัตถุเดียวกัน
>>> 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
ไม่สามารถเขียนทับได้ใน Python เวอร์ชั่นเก่ากว่า (ก่อนหน้า 2.4) เป็นไปได้ที่จะมอบหมายใหม่None
แต่ไม่สามารถกำหนดได้อีกต่อไป ไม่ได้เป็นคุณลักษณะคลาสหรือในขอบเขตของฟังก์ชั่น
# 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
ดังนั้นจึงปลอดภัยที่จะสมมติว่าNone
การอ้างอิงทั้งหมดเหมือนกัน ไม่มี None
"กำหนดเอง"
None
ใช้งานis
โอเปอเรเตอร์เมื่อเขียนโค้ดคุณอาจถูกล่อลวงให้ทดสอบNonenessเช่นนี้:
if value==None:
pass
หรือเพื่อทดสอบความเท็จเช่นนี้
if not value:
pass
คุณต้องเข้าใจความหมายและทำไมมันมักจะเป็นความคิดที่ดีที่จะชัดเจน
None
ทำไมต้องทำเช่นนี้
value is None
ค่อนข้างมากกว่า
value==None
ครั้งแรกเทียบเท่ากับ:
id(value)==id(None)
value==None
ในความเป็นจริงแล้วนิพจน์นั้นถูกนำไปใช้เช่นนี้
value.__eq__(None)
หากมูลค่าเป็นจริงNone
คุณจะได้รับสิ่งที่คาดหวัง
>>> nothing = function_that_does_nothing()
>>> nothing.__eq__(None)
True
ในกรณีทั่วไปส่วนใหญ่ผลลัพธ์จะเหมือนกัน แต่ __eq__()
วิธีการเปิดประตูที่เป็นช่องว่างที่รับประกันความถูกต้องเนื่องจากมันสามารถถูกแทนที่ในชั้นเรียนเพื่อให้พฤติกรรมพิเศษ
พิจารณาคลาสนี้
>>> class Empty(object):
... def __eq__(self, other):
... return not other
ดังนั้นคุณลองNone
และใช้งานได้
>>> empty = Empty()
>>> empty==None
True
แต่แล้วมันก็ยังใช้งานได้กับสตริงว่าง
>>> empty==''
True
และยัง
>>> ''==None
False
>>> empty is None
False
None
เป็นบูลีนการทดสอบสองครั้งต่อไปนี้
if value:
# do something
if not value:
# do something
ในความเป็นจริงการประเมินเป็น
if bool(value):
# do something
if not bool(value):
# do something
None
คือ "falsey" หมายถึงว่าถ้าโยนบูลมันจะกลับมาFalse
และถ้านำไปใช้ประกอบการก็จะกลับnot
แต่ทราบว่ามันไม่ใช่คุณสมบัติที่จะไม่ซ้ำกันTrue
None
นอกเหนือไปจากFalse
ตัวเองทรัพย์สินที่ใช้ร่วมกันโดยรายการที่ว่างเปล่า tuples, ชุด dicts สายเช่นเดียวกับ 0 และวัตถุทั้งหมดออกจากชั้นเรียนที่ใช้วิธีวิเศษที่จะกลับมา__bool__()
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
ดังนั้นเมื่อทำการทดสอบตัวแปรด้วยวิธีต่อไปนี้ให้ระวังสิ่งที่คุณกำลังรวมหรือแยกออกจากการทดสอบ:
def some_function(value=None):
if not value:
value = init_value()
ในข้างต้นคุณหมายถึงการโทรinit_value()
เมื่อค่าถูกตั้งค่าเป็นพิเศษNone
หรือคุณหมายถึงค่าที่ตั้งเป็น0
หรือสตริงว่างหรือรายการว่างควรเรียกการเริ่มต้น อย่างที่ฉันพูด ในขณะที่มันมักจะเป็นในกรณีที่งูใหญ่อย่างชัดเจนจะดีกว่าโดยปริยาย
None
ในทางปฏิบัติNone
ใช้เป็นค่าสัญญาณNone
มีสถานะพิเศษใน Python มันเป็นค่าพื้นฐานที่ชื่นชอบเพราะอัลกอริทึมจำนวนมากถือว่าเป็นค่าที่ไม่ธรรมดา ในสถานการณ์เช่นนี้มันสามารถใช้เป็นธงเพื่อส่งสัญญาณว่าเงื่อนไขนั้นต้องการการจัดการพิเศษ (เช่นการตั้งค่าเริ่มต้น)
คุณสามารถกำหนดNone
ให้กับอาร์กิวเมนต์คำหลักของฟังก์ชันและทดสอบอย่างชัดเจน
def my_function(value, param=None):
if param is None:
# do something outrageous!
คุณสามารถส่งคืนเป็นค่าเริ่มต้นเมื่อพยายามเข้าถึงแอตทริบิวต์ของวัตถุแล้วทดสอบอย่างชัดเจนก่อนทำสิ่งพิเศษ
value = getattr(some_obj, 'some_attribute', None)
if value is None:
# do something spectacular!
ตามค่าเริ่มต้นget()
เมธอดของพจนานุกรมจะส่งคืนNone
เมื่อพยายามเข้าถึงคีย์ที่ไม่มีอยู่:
>>> some_dict = {}
>>> value = some_dict.get('foo')
>>> value is None
True
หากคุณพยายามที่จะเข้าถึงมันโดยใช้เครื่องหมายห้อยKeyError
จะเพิ่มขึ้น
>>> value = some_dict['foo']
KeyError: 'foo'
ในทำนองเดียวกันหากคุณพยายามที่จะปรากฏรายการที่ไม่มีอยู่
>>> value = some_dict.pop('foo')
KeyError: 'foo'
ซึ่งคุณสามารถระงับด้วยค่าเริ่มต้นที่มักจะตั้งค่า None
value = some_dict.pop('foo', None)
if value is None:
# booom!
None
ใช้เป็นทั้งค่าสถานะและค่าที่ถูกต้องการใช้งานที่อธิบายด้านบนของการNone
ใช้เมื่อไม่ถือว่าเป็นค่าที่ถูกต้อง แต่มีสัญญาณมากกว่าที่จะทำสิ่งพิเศษ มีบางสถานการณ์ที่บางครั้งมันก็สำคัญที่ต้องรู้ว่าNone
มาจากไหนเพราะถึงแม้ว่ามันจะถูกใช้เป็นสัญญาณ แต่ก็อาจเป็นส่วนหนึ่งของข้อมูล
เมื่อคุณเคียวรีวัตถุสำหรับแอททริบิวต์ที่มีgetattr(some_obj, 'attribute_name', None)
การเรียกคืนNone
ไม่ได้บอกคุณว่าแอททริบิวที่คุณพยายามเข้าถึงนั้นถูกตั้งค่าเป็นNone
หรือว่ามันหายไปจากวัตถุโดยสิ้นเชิง สถานการณ์เดียวกันเมื่อมีการเข้าถึงที่สำคัญจากพจนานุกรมเหมือนที่some_dict.get('some_key')
คุณไม่ทราบว่าจะหายไปหรือถ้ามันตั้งเพียงเพื่อsome_dict['some_key']
None
หากคุณต้องการข้อมูลนั้นวิธีปกติในการจัดการนี้คือพยายามเข้าถึงแอตทริบิวต์หรือคีย์โดยตรงจากภายในtry/except
โครงสร้าง:
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)
ในทำนองเดียวกันกับ 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)
ตัวอย่างสองตัวอย่างข้างต้นแสดงวิธีจัดการกรณีวัตถุและพจนานุกรมสิ่งที่เกี่ยวกับฟังก์ชั่น? สิ่งเดียวกัน แต่เราใช้อาร์กิวเมนต์คำหลักดอกจันคู่กับส่วนท้าย:
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
ใช้เป็นค่าที่ถูกต้องเท่านั้นหากคุณพบว่าโค้ดของคุณถูกทิ้งด้วยtry/except
รูปแบบข้างต้นเพียงเพื่อแยกความแตกต่างระหว่างNone
ค่าสถานะและNone
ข้อมูลจากนั้นใช้ค่าทดสอบอื่น มีรูปแบบที่แทรกค่าที่อยู่นอกชุดของค่าที่ถูกต้องซึ่งเป็นส่วนหนึ่งของข้อมูลในโครงสร้างข้อมูลและใช้เพื่อควบคุมและทดสอบเงื่อนไขพิเศษ (เช่นขอบเขตรัฐ ฯลฯ ) ค่าดังกล่าวเรียกว่าSentinelและสามารถใช้วิธีที่None
ใช้เป็นสัญญาณได้ มันง่ายมากที่จะสร้าง Sentinel ใน Python
undefined = object()
undefined
วัตถุดังกล่าวข้างต้นมีความเป็นเอกลักษณ์และไม่ได้ทำอะไรมากที่อาจจะมีความสนใจในการเขียนโปรแกรมก็จึงเปลี่ยนที่ดีสำหรับการNone
เป็นธง คำเตือนบางอย่างใช้เพิ่มเติมเกี่ยวกับหลังจากรหัส
ด้วยฟังก์ชั่น
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
พร้อม dict
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
ด้วยวัตถุ
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
อย่างที่ฉันได้กล่าวถึงยามรักษาการณ์ก่อนหน้านี้มาพร้อมกับคำเตือนบางอย่าง ก่อนอื่นพวกเขาไม่ใช่คำหลักNone
ดังนั้น python จึงไม่ปกป้อง คุณสามารถเขียนทับข้อความundefined
ด้านบนของคุณได้ทุกที่ทุกเวลาในโมดูลที่กำหนดไว้ดังนั้นโปรดใช้ความระมัดระวังในการเปิดเผยและใช้งาน ถัดไปอินสแตนซ์ที่ส่งกลับโดยobject()
ไม่ใช่ซิงเกิลตันถ้าคุณทำการโทรนั้น 10 ครั้งคุณจะได้รับ 10 วัตถุที่แตกต่างกัน ในที่สุดการใช้ Sentinel นั้นมีความเป็นไปได้สูงมาก Sentinel มีความเฉพาะเจาะจงกับไลบรารีที่ใช้ในและโดยทั่วไปขอบเขตดังกล่าวควรถูก จำกัด ไว้ที่ internals ของห้องสมุด ไม่ควร "รั่ว" ออก รหัสภายนอกควรตระหนักถึงมันหากวัตถุประสงค์ของพวกเขาคือการขยายหรือเสริม API ของห้องสมุด
มันไม่ได้เรียกว่าเป็นโมฆะในภาษาอื่น ๆ None
แต่ มีเพียงอินสแตนซ์เดียวของวัตถุนี้เสมอดังนั้นคุณสามารถตรวจสอบความเทียบเท่ากับx is None
(การเปรียบเทียบตัวตน) แทนที่จะเป็นx == None
หากคุณต้องการ
None
ใหม่ ถ้าอย่างนั้นคนฉลาดที่เปรียบเทียบกับทุกคนNoneType
จะได้ชัยชนะ!
ใน Python เพื่อแสดงถึงการไม่มีค่าคุณสามารถใช้ค่าNone ( types.NoneType.None ) สำหรับวัตถุและ"" (หรือlen () == 0 ) สำหรับสตริง ดังนั้น:
if yourObject is None: # if yourObject == None:
...
if yourString == "": # if yourString.len() == 0:
...
เกี่ยวกับความแตกต่างระหว่าง "==" และ "คือ" การทดสอบเอกลักษณ์ของวัตถุโดยใช้ "==" น่าจะเพียงพอ อย่างไรก็ตามเนื่องจากการดำเนินการ "คือ" ถูกกำหนดให้เป็นการดำเนินการระบุตัวตนวัตถุจึงอาจถูกต้องมากกว่าที่จะใช้แทนที่จะเป็น "==" ไม่แน่ใจว่ามีความแตกต่างความเร็วหรือไม่
อย่างไรก็ตามคุณสามารถดู:
0 == false
ส่งคืนtrue
เนื่องจากตัวดำเนินการ double-equals พิมพ์ coercion อย่างไรก็ตามด้วยตัวดำเนินการสามเท่า0 === false
จะส่งคืนfalse
เนื่องจาก 'number' และ 'boolean' เป็นประเภทที่แตกต่างกัน
true
เงื่อนไข ใน Rust and Go 0
และfalse
เป็นประเภทที่แตกต่างกันซึ่งไม่สามารถนำมาเปรียบเทียบเพื่อความเท่าเทียมกันได้
Null เป็นวัตถุชนิดพิเศษเช่น:
>>>type(None)
<class 'NoneType'>
คุณสามารถตรวจสอบว่าวัตถุอยู่ในคลาส 'NoneType' หรือไม่:
>>>variable = None
>>>variable is None
True
ข้อมูลเพิ่มเติมสามารถดูได้ที่Python Docs
ตามการทดสอบค่าความจริง 'ไม่มี' ทดสอบโดยตรงเป็น FALSE ดังนั้นนิพจน์ที่ง่ายที่สุดจะพอเพียง:
if not foo:
True
สำหรับการใด ๆค่า falsy None
ไม่เพียง
egg is None
มากกว่าegg == None
: หลังสามารถมากเกินไปและมีแนวโน้มที่จะทำลายเมื่อเปรียบเทียบกับวัตถุที่ถูกต้องกับไม่มี (ขึ้นอยู่กับวิธีการที่จะดำเนินการ แต่คุณไม่ได้คาดหวังว่าทุกคนที่จะเปรียบเทียบเช่นเดียวกันกับที่ไม่มีใครเข้าบัญชีคุณ?) ในขณะที่is
ทำงานเหมือนเดิมเสมอ