2009-08-24 16 views
635

Tôi tự hỏi những gì là tốt hơn để làm:'has_key()' hoặc 'in'?

d = {'a': 1, 'b': 2} 
'a' in d 
True 

hay:

d = {'a': 1, 'b': 2} 
d.has_key('a') 
True 

Trả lời

885

in là pythonic chắc chắn hơn.

Thực tế, has_key() was removed in Python 3.x.

+2

Như Ngoài ra, trong Python 3, để kiểm tra sự tồn tại trong các giá trị, thay vì các phím, hãy thử >>> 1 trong d.values ​​() – riza

+140

Một nửa thông tin cần tránh là đảm bảo bạn thực hiện: "key in some_dict "thay vì" khóa trong some_d ict.keys() ". Cả hai đều tương đương ngữ nghĩa, nhưng hiệu suất khôn ngoan sau này là chậm hơn nhiều (O (n) vs O (1)). Tôi đã thấy mọi người làm "trong dict.keys()" nghĩ rằng nó rõ ràng hơn và do đó tốt hơn. –

+2

'in' hoạt động với 2.6 quá phải không? – Logan

64

Theo python docs:

has_key() được phản đối ủng hộ key in d.

214

in thắng tay xuống, không chỉ ở sang trọng (và không được phản đối ;-) mà còn ở hiệu suất, ví dụ:

$ 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 

Trong khi quan sát sau đây không phải là luôn đúng, bạn sẽ nhận thấy rằng thường là, bằng Python, giải pháp nhanh hơn là thanh lịch hơn và Pythonic; đó là lý do tại sao -mtimeit là SO hữu ích - nó không chỉ về tiết kiệm một trăm nano giây ở đây và ở đó -!)

+4

Cảm ơn điều này, đã xác minh rằng "trong some_dict" là trong thực tế O (1) dễ dàng hơn nhiều (thử tăng 99 để nói năm 1999, và bạn sẽ thấy thời gian chạy là như nhau). –

+2

'has_key' có vẻ là O (1). –

12

has_key là một phương pháp từ điển, nhưng in sẽ làm việc trên bất kỳ bộ sưu tập, và thậm chí khi __contains__ là mất tích, in sẽ sử dụng bất kỳ phương pháp nào khác để lặp lại bộ sưu tập để tìm hiểu.

+1

Và cũng hoạt động trên các trình lặp "x in xrange (90, 200) <=> 90 <= x <200" – u0b34a0f6ae

+0

…: Điều này có vẻ như một ý tưởng rất tồi: 50 hoạt động thay vì 2. –

34

Sử dụng dict.has_key() nếu (và chỉ nếu) mã của bạn được yêu cầu phải được chạy bằng các phiên bản Python sớm hơn 2.3 (khi key in dict được giới thiệu).

+1

Bản cập nhật WebSphere năm 2013 sử dụng Jython 2.1 như ngôn ngữ kịch bản chính của nó. Vì vậy, đây là tiếc là vẫn còn một điều hữu ích cần lưu ý, năm năm sau khi bạn ghi nhận nó. – ArtOfWarfare

18

Có một ví dụ trong đó in thực sự giết hiệu suất của bạn.

Nếu bạn sử dụng in trên O (1) chứa mà chỉ thực hiện __getitem__has_key() nhưng không __contains__ bạn sẽ biến một O (1) tìm kiếm thành một O (N) tìm kiếm (tương in rơi trở lại để tìm kiếm tuyến tính qua __getitem__).

Fix rõ ràng là tầm thường:

def __contains__(self, x): 
    return self.has_key(x) 
10

Python 2.x hỗ trợ has_key().

Hỗ trợ Python 2.3+ và Python 3.x in.

5

Nếu ý định của bạn là sử dụng một giá trị mặc định trong trường hợp một chìa khóa không có trong từ điển thì

my_dict.get('key') or default_value 

là một cách để bỏ qua việc kiểm tra in. get trả về None nếu khóa không có trong từ điển. Tốc độ cũng là O (1) như với việc sử dụng in.

Bạn cũng có thể sử dụng

my_dict.get('key', default_value) 

nhưng tôi thấy rằng ít có thể đọc được.

+2

Trong khi điều này là đúng, tôi không chắc chắn những gì nó đã làm với câu hỏi. – cpburnz

+2

Tôi rất muốn sử dụng phiên bản thứ hai. Đối với cái đầu tiên, bạn sẽ nhận được '' default_value'' nếu khóa xuất hiện nhưng giá trị chuyển thành '' False'' ('' None'', '' False'', '' 0'') – greschd

0

API trông cách nó vì một lý do ... Sử dụng các API kiểu dựng sẵn như tài liệu là Pythonic ...

Bạn thường nên làm my_dict.get('key', default_value) hơn my_dict.get('key') or default_value.

Trường hợp ngoại lệ sẽ là trường hợp lẻ muốn thay thế tất cả các giá trị sai tương đương (0, '', [] vv) trở về từ my_dict với default_value.

Thực ra, nếu ý định là để có được một giá trị mặc định từ một dict, tại sao không sử dụng collections.defaultdict thay vì được xây dựng dict?

>>> from collections import defaultdict 
>>> d42 = defaultdict(lambda: 42) 
>>> d42['x'] = 18 
>>> d42['x'] 
18 
>>> d42['y'] 
42 

Các usecase phổ biến nhất cho defaultdicts có lẽ là với các loại danh sách, ví dụ:

>>> dl = defaultdict(list) 
>>> for x, y in some_list_of_tuples: 
...  dl[x].append(y) 
>>> 
+3

Trong khi là đúng, tôi không chắc nó phải làm gì với câu hỏi. – cpburnz

+0

Hãy xem xét những điều sau đây: 'my_dict.get (khóa, default_val_fn (khóa))' vs 'my_dict.get (khóa) hoặc default_val_fn (khóa)'. Trong trường hợp thứ hai, 'default_val_fn' là ** only ** được gọi nếu khóa không được tìm thấy trong từ điển, trong khi trong trường hợp đầu tiên, nó được gọi (như python cần đánh giá tất cả các đối số cho hàm' get'). Điều này có thể hiệu quả hơn, đặc biệt là nếu bạn không cần phải lo lắng về tương đương giả. – Bahrom

10

Giải pháp cho dict.has_key() bị phản đối, sử dụng 'trong' - soạn thảo văn bản siêu việt 3

ở đây tôi đã lấy một ví dụ về từ điển có tên là 'tuổi' -

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" 
+3

Đúng, nhưng nó đã được trả lời, chào mừng bạn đến với Stackoveflow, cảm ơn ví dụ, luôn luôn kiểm tra câu trả lời! – igorgue

+0

@igorgue im không chắc chắn về các downvotes với cô ấy. Câu trả lời của cô ấy có thể tương tự như câu trả lời đã được trả lời, nhưng cô ấy đưa ra một ví dụ. Isnt xứng đáng để trở thành một câu trả lời của SO? –

+0

@AkshatAgarwal No: câu hỏi đã có một ví dụ. –

5

Mở rộng trên Alex kiểm tra hiệu suất Martelli với ý kiến ​​Adam Parkin của ...

$ 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 
4

Nếu bạn có một cái gì đó giống như

t.has_key(ew) 

thay đổi này nó xuống dưới để chạy trên Python 3.x trở lên

key = ew 
if key not in t 
Các vấn đề liên quan