2011-12-19 34 views
14
>>> False in [0] 
True 
>>> type(False) == type(0) 
False 

Lý do tôi stumbled khi này:Python "in" không kiểm tra loại?

Đối với đơn vị thử nghiệm của tôi, tôi tạo ra danh sách các giá trị mẫu hợp lệ và không hợp lệ cho mỗi loại của tôi. (Tôi có nghĩa là, chúng không phải là 100% tương đương với các loại trăn) Vì vậy, tôi muốn lặp lại danh sách tất cả các giá trị và mong đợi chúng vượt qua nếu chúng nằm trong các giá trị hợp lệ của tôi, và mặt khác, thất bại nếu họ không. Điều đó không làm việc rất tốt bây giờ:

>>> valid_values = [-1, 0, 1, 2, 3] 
>>> invalid_values = [True, False, "foo"] 
>>> for value in valid_values + invalid_values: 
...  if value in valid_values: 
...   print 'valid value:', value 
... 
valid value: -1 
valid value: 0 
valid value: 1 
valid value: 2 
valid value: 3 
valid value: True 
valid value: False 

Tất nhiên là tôi không đồng ý với hai giá trị 'hợp lệ' ngoái.

Điều này có nghĩa là tôi thực sự phải lặp qua giá trị hợp lệ của mình và so sánh loại không?

+0

+1 Hmm, tôi không bao giờ mặc dù con trăn của 'in' không kiểm tra loại. Rất thú vị . . . – OnesimusUnbound

+0

@BenJames, hmm, tôi tự hỏi làm thế nào nó sẽ phá vỡ việc gõ vịt bằng Python? – OnesimusUnbound

Trả lời

4

Như những người khác đã viết, "trong" mã số không làm những gì bạn muốn nó làm. Bạn sẽ cần cái gì khác.

Nếu bạn thực sự muốn có một kiểm tra loại (trong đó việc kiểm tra là chính xác cùng loại) sau đó bạn có thể bao gồm các loại trong danh sách:

>>> valid_values = [(int, i) for i in [-1, 0, 1, 2, 3]] 
>>> invalid_values = [True, False, "foo"] 
>>> for value in [v[1] for v in valid_values] + invalid_values: 
... if (type(value), value) in valid_values: 
...  print value, "is valid" 
... else: 
...  print value, "is invalid" 
... 
-1 is valid 
0 is valid 
1 is valid 
2 is valid 
3 is valid 
True is invalid 
False is invalid 
foo is invalid 
>>> 

Xử lý phân nhóm là khó khăn hơn một chút, và sẽ phụ thuộc về những gì bạn muốn làm.

+0

Tôi đã sử dụng giải pháp của bạn để ngăn chặn vòng lặp bổ sung. Nhưng tôi đã đổi thành: valid_values ​​= [(loại (v), v) cho v trong [-1, 0, 1, 2, 3]] –

15

Vấn đề không phải là loại kiểm tra bị thiếu, nhưng vì trong Python bool là một phân lớp của int. Cố gắng này:

>>> False == 0 
True 
>>> isinstance(False, int) 
True 
+0

Tôi không phàn nàn về False == 0, nhưng chỉ về thực tế là "trong" sẽ không kiểm tra loại. –

+6

'in' trả về true nếu một mục trong chuỗi là' bằng' đối tượng được yêu cầu. Vì vậy, vấn đề của bạn không phải là toán tử 'in', mà là toán tử' == '. – Constantinius

+0

Tôi chỉ muốn có một kiểm tra danh tính ở đó. Có cách nào để làm điều này mà không sử dụng một vòng lặp? –

6

Theo documentation, __contains__ được thực hiện bằng cách duyệt qua các bộ sưu tập và kiểm tra các yếu tố của ==. Do đó, vấn đề thực tế là do thực tế, rằng False == 0True.

+0

Đối với pedantic ... nó kiểm tra phương thức '' __contains __ (self, thing) '' trước, * sau đó * quay trở lại để lặp qua đối tượng. Đối với một '' list'' thực sự, có '' __contains__'', do đó là dự phòng. –

+0

@GreggLind bạn tất nhiên là đúng.Tuy nhiên, tôi không thể tìm thấy một định nghĩa tốt hơn về "trong". Để phù hợp với nguyên tắc ít ngạc nhiên nhất, một phương thức '__contains__' bị quá tải nên làm điều tương tự. –

+1

Tôi đã có điều này cắn tôi khi xác định loại bỏ ngăn chặn một máy phát điện và/hoặc chạy mãi mãi. Tránh được bằng cách viết * thông minh hơn * '' __contains__''. (nghĩ về những thứ như '' itertools.cycle'') –

3

True == 1False == 0 thật khó để phân biệt giữa hai loại.

Một cách tiếp cận có thể nhưng xấu xí (mà cũng không được bảo đảm để làm việc trong tất cả các hiện thực Python nhưng nên OK trong CPython):

>>> for value in valid_values + invalid_values: 
... if value in valid_values and not any(v is value for v in invalid_values): 
...  print ('valid value:', value) 
... 
valid value: -1 
valid value: 0 
valid value: 1 
valid value: 2 
valid value: 3 
+0

Tôi muốn ngăn chặn một vòng lặp khác. Vì kiểm tra này sẽ được thực hiện khá thường xuyên trong hầu hết các thử nghiệm của tôi. –