Sự khác nhau giữa isinstance()
và type()
trong Python?
Kiểm tra loại với
isinstance(obj, Base)
cho phép các thể hiện của các lớp con và nhiều cơ sở có thể:
isinstance(obj, (Base1, Base2))
trong khi kiểm tra kiểu với
type(obj) is Base
chỉ hỗ trợ các loại tham chiếu.
Là một sidenote, is
có khả năng thích hợp hơn
type(obj) == Base
bởi vì các lớp học là singletons.
Tránh kiểm tra kiểu - sử dụng Đa hình (gõ vịt)
Trong Python, thông thường bạn muốn cho phép bất kỳ loại nào cho các đối số của mình, xử lý nó như mong đợi và nếu đối tượng không hoạt động như mong đợi, nó sẽ đưa ra một lỗi thích hợp. Điều này được gọi là đa hình, còn được gọi là gõ vịt.
def function_of_duck(duck):
duck.quack()
duck.swim()
Nếu đoạn mã trên hoạt động, chúng ta có thể đoán rằng đối số của chúng ta là một con vịt. Vì vậy, chúng ta có thể vượt qua trong những thứ khác là các loại vịt thực tế:
function_of_duck(mallard)
hoặc hoạt động như một con vịt:
function_of_duck(object_that_quacks_and_swims_like_a_duck)
và mã của chúng tôi vẫn hoạt động.
Tuy nhiên, có một số trường hợp mong muốn kiểm tra kiểu rõ ràng. Có lẽ bạn có những điều hợp lý để làm với các loại đối tượng khác nhau. Ví dụ, đối tượng Pandas Dataframe có thể được xây dựng từ các bản ghi hoặc bản ghi. Trong trường hợp như vậy, mã của bạn cần biết loại đối số nào đang nhận để nó có thể xử lý đúng.
Vì vậy, để trả lời câu hỏi:
Sự khác nhau giữa isinstance()
và type()
trong Python?
Cho phép tôi chứng minh sự khác biệt:
type
Giả sử bạn cần đảm bảo một hành vi nhất định nếu hàm của bạn có một loại đối số nhất định (trường hợp sử dụng chung cho các hàm tạo). Nếu bạn kiểm tra loại như thế này:
def foo(data):
'''accepts a dict to construct something, string support in future'''
if type(data) is not dict:
# we're only going to test for dicts for now
raise ValueError('only dicts are supported for now')
Nếu chúng ta cố gắng vượt qua trong một dict là một lớp con của dict
(như chúng ta có thể, nếu chúng ta hy vọng mã của chúng ta tuân theo nguyên tắc Thay thế Liskov , các kiểu con có thể được thay thế cho các loại) thì mã của chúng ta bị phá vỡ!:
from collections import OrderedDict
foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))
gây ra một lỗi!
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in foo
ValueError: argument must be a dict
isinstance
Nhưng nếu chúng tôi sử dụng isinstance
, chúng tôi có thể hỗ trợ Thay thế Liskov!:
def foo(a_dict):
if not isinstance(a_dict, dict):
raise ValueError('argument must be a dict')
return a_dict
foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))
trả lại OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])
Các lớp cơ sở trừu tượng
Trong thực tế, chúng ta có thể làm tốt hơn nữa. collections
cung cấp các lớp cơ sở trừu tượng thực thi các giao thức tối thiểu cho các loại khác nhau. Trong trường hợp của chúng tôi, nếu chúng tôi chỉ mong đợi Mapping
giao thức, chúng tôi có thể thực hiện các thao tác sau và mã của chúng tôi thậm chí còn linh hoạt hơn:
from collections import Mapping
def foo(a_dict):
if not isinstance(a_dict, Mapping):
raise ValueError('argument must be a dict')
return a_dict
Trả lời bình luận:
Cần lưu ý rằng loại có thể được sử dụng để kiểm tra đối với nhiều lớp bằng cách sử dụng type(obj) in (A, B, C)
Có, bạn có thể kiểm tra sự bằng nhau của các loại, nhưng thay vì ở trên, hãy sử dụng nhiều cơ sở cho luồng điều khiển, trừ khi bạn chỉ cho phép các loại đó:
isinstance(obj, (A, B, C))
Sự khác biệt, một lần nữa, là isinstance
hỗ trợ các lớp con có thể được thay thế cho cha mẹ mà không phá vỡ chương trình, một thuộc tính được gọi là thay thế Liskov.
Tuy nhiên, thậm chí tốt hơn, đảo ngược sự phụ thuộc của bạn và không kiểm tra các loại cụ thể nào cả.
Phần kết luận
Vì vậy, vì chúng tôi muốn hỗ trợ thay thế các lớp con, trong hầu hết các trường hợp, chúng tôi muốn tránh kiểm tra type
kiểu và thích kiểm tra kiểu hơn isinstance
- trừ khi bạn thực sự cần biết chính xác về một thể hiện.
str
vàunicode
(nơi bạn chỉ có thể kiểm trabasestring
), bạn có thể sử dụng bộ dữ liệu để kiểm tra đối với nhiều loại. Để kiểm tra nếusomething
làint
hoặcstr
sử dụngisinstance(something, (int, str))
.