ฉันสงสัยว่าจะทำอย่างไรดีกว่า:
d = {'a': 1, 'b': 2}
'a' in d
True
หรือ:
d = {'a': 1, 'b': 2}
d.has_key('a')
True
ฉันสงสัยว่าจะทำอย่างไรดีกว่า:
d = {'a': 1, 'b': 2}
'a' in d
True
หรือ:
d = {'a': 1, 'b': 2}
d.has_key('a')
True
คำตอบ:
in
แน่นอนยิ่งกว่า pythonic
ในความเป็นจริงhas_key()
จะถูกลบออกในหลาม 3.x
keys()
เป็นเพียงมุมมองแบบ set-like ลงในพจนานุกรมแทนที่จะเป็นสำเนาดังนั้นx in d.keys()
O (1) ยังคงx in d
เป็น Pythonic มากกว่า
x in d.keys()
ต้องสร้างและทำลายวัตถุชั่วคราวพร้อมกับการจัดสรรหน่วยความจำที่เกี่ยวข้องซึ่งx in d.keys()
เป็นเพียงการดำเนินการทางคณิตศาสตร์ (คำนวณแฮช) และทำการค้นหา โปรดทราบว่าd.keys()
มีเพียงประมาณ 10 เท่าเท่านั้นซึ่งยังไม่นานจริง ๆ ฉันยังไม่ได้ตรวจสอบ แต่ฉันก็ยังค่อนข้างแน่ใจว่ามันเป็นเพียง O (1)
in
ชนะมือลงไม่ใช่แค่ในความสง่างาม (และไม่ถูกคัดค้าน ;-) แต่รวมถึงประสิทธิภาพเช่น:
$ python -mtimeit -s'd=dict.fromkeys(range(99))' '12 in d'
10000000 loops, best of 3: 0.0983 usec per loop
$ python -mtimeit -s'd=dict.fromkeys(range(99))' 'd.has_key(12)'
1000000 loops, best of 3: 0.21 usec per loop
ในขณะที่การสังเกตต่อไปนี้ไม่เป็นความจริงเสมอไปคุณจะสังเกตได้ว่าโดยปกติแล้วใน Python โซลูชันที่เร็วกว่านั้นจะดูดีและ Pythonic นั่นเป็นเหตุผลว่าทำไมจึง-mtimeit
มีประโยชน์ - ไม่ใช่แค่เกี่ยวกับการบันทึกหนึ่งร้อยนาโนวินาทีที่นี่และที่นั่น! -)
has_key
ดูเหมือนจะเป็น O (1) ด้วย
อ้างอิงจากเอกสารหลาม:
has_key()
key in d
จะเลิกในความโปรดปรานของ
has_key()
ถูกลบออกใน Python 3
ใช้dict.has_key()
ถ้า (และเฉพาะในกรณี) รหัสของคุณจะต้องสามารถรันได้โดย Python เวอร์ชันที่เก่ากว่า 2.3 (เมื่อkey in dict
ถูกนำมาใช้)
มีตัวอย่างหนึ่งที่in
ฆ่าประสิทธิภาพได้จริง
ถ้าคุณใช้in
ในโอ (1) ภาชนะที่มีเพียงการดำเนินการ__getitem__
และhas_key()
แต่ไม่__contains__
ว่าคุณจะเปิด O (1) ค้นหาเป็น O (N) ค้นหา (ตามที่in
อยู่กลับไปยังการค้นหาเชิงเส้นผ่าน__getitem__
)
เห็นได้ชัดว่าการแก้ไขเล็กน้อย:
def __contains__(self, x):
return self.has_key(x)
has_key()
เป็นที่เฉพาะเจาะจงกับงูหลาม 2 พจนานุกรม in
/ __contains__
เป็น API ที่ถูกต้องที่จะใช้; สำหรับคอนเทนเนอร์ที่ไม่สามารถหลีกเลี่ยงการสแกนเต็มรูปแบบจะไม่มีhas_key()
วิธีการใด ๆอยู่แล้วและหากมีวิธี O (1) วิธีนั้นจะใช้เฉพาะกรณีและขึ้นอยู่กับผู้พัฒนาที่จะเลือกประเภทข้อมูลที่เหมาะสมสำหรับปัญหา
has_key
เป็นวิธีพจนานุกรม แต่in
จะทำงานกับคอลเลกชันใด ๆ และแม้__contains__
จะหายไปin
จะใช้วิธีอื่น ๆ เพื่อทำซ้ำคอลเลกชันเพื่อค้นหา
in
ทดสอบกับrange
วัตถุ ผมไม่แน่ใจว่าเกี่ยวกับประสิทธิภาพในการใช้ในหลาม 2 xrange
แม้ว่า ;)
__contains__
สามารถคำนวณได้เล็กน้อยว่าค่าอยู่ในช่วงหรือไม่
range
อินสแตนซ์ใหม่ทุกครั้ง การใช้อินสแตนซ์ที่มีอยู่ก่อนหน้าเดียวการทดสอบ "จำนวนเต็มในช่วง" จะเร็วขึ้นประมาณ 40% ในการกำหนดเวลาของฉัน
โซลูชัน dict.has_key () เลิกใช้แล้วใช้ 'ใน' - โปรแกรมแก้ไขข้อความประเสริฐ 3
ที่นี่ฉันได้นำตัวอย่างของพจนานุกรมชื่อ 'วัย' -
ages = {}
# Add a couple of names to the dictionary
ages['Sue'] = 23
ages['Peter'] = 19
ages['Andrew'] = 78
ages['Karren'] = 45
# use of 'in' in if condition instead of function_name.has_key(key-name).
if 'Sue' in ages:
print "Sue is in the dictionary. She is", ages['Sue'], "years old"
else:
print "Sue is not in the dictionary"
ขยายการทดสอบประสิทธิภาพของ Alex Martelli ด้วยความคิดเห็นของ Adam Parkin ...
$ python3.5 -mtimeit -s'd=dict.fromkeys(range( 99))' 'd.has_key(12)'
Traceback (most recent call last):
File "/usr/local/Cellar/python3/3.5.2_3/Frameworks/Python.framework/Versions/3.5/lib/python3.5/timeit.py", line 301, in main
x = t.timeit(number)
File "/usr/local/Cellar/python3/3.5.2_3/Frameworks/Python.framework/Versions/3.5/lib/python3.5/timeit.py", line 178, in timeit
timing = self.inner(it, self.timer)
File "<timeit-src>", line 6, in inner
d.has_key(12)
AttributeError: 'dict' object has no attribute 'has_key'
$ python2.7 -mtimeit -s'd=dict.fromkeys(range( 99))' 'd.has_key(12)'
10000000 loops, best of 3: 0.0872 usec per loop
$ python2.7 -mtimeit -s'd=dict.fromkeys(range(1999))' 'd.has_key(12)'
10000000 loops, best of 3: 0.0858 usec per loop
$ python3.5 -mtimeit -s'd=dict.fromkeys(range( 99))' '12 in d'
10000000 loops, best of 3: 0.031 usec per loop
$ python3.5 -mtimeit -s'd=dict.fromkeys(range(1999))' '12 in d'
10000000 loops, best of 3: 0.033 usec per loop
$ python3.5 -mtimeit -s'd=dict.fromkeys(range( 99))' '12 in d.keys()'
10000000 loops, best of 3: 0.115 usec per loop
$ python3.5 -mtimeit -s'd=dict.fromkeys(range(1999))' '12 in d.keys()'
10000000 loops, best of 3: 0.117 usec per loop
หากคุณมีสิ่งนี้:
t.has_key(ew)
เปลี่ยนเป็นด้านล่างเพื่อใช้งานบน Python 3.X ขึ้นไป:
key = ew
if key not in t
t.has_key(ew)
ส่งคืนTrue
ถ้าการew
อ้างอิงค่าเป็นกุญแจสำคัญในพจนานุกรมด้วย key not in t
ส่งคืนTrue
ถ้าค่าไม่ได้อยู่ในพจนานุกรม นอกจากนี้key = ew
นามแฝงนั้นซ้ำซ้อนมาก if ew in t
การสะกดคำที่ถูกต้องคือ ซึ่งเป็นสิ่งที่คำตอบที่ยอมรับจาก 8 ปีก่อนบอกคุณแล้ว