Cách tốt nhất để kiểm tra xem một đối tượng nhất định có thuộc loại nhất định không? Làm thế nào về việc kiểm tra xem đối tượng kế thừa từ một loại nhất định?
Hãy nói rằng tôi có một đối tượng o
. Làm thế nào để tôi kiểm tra xem nó là một str
?
Cách tốt nhất để kiểm tra xem một đối tượng nhất định có thuộc loại nhất định không? Làm thế nào về việc kiểm tra xem đối tượng kế thừa từ một loại nhất định?
Hãy nói rằng tôi có một đối tượng o
. Làm thế nào để tôi kiểm tra xem nó là một str
?
Câu trả lời:
Để kiểm tra xem o
là một thể hiện của str
hoặc bất kỳ lớp con nào str
, hãy sử dụng isinstance (đây sẽ là cách "chính tắc"):
if isinstance(o, str):
Để kiểm tra xem loại của o
có chính xác str
không (loại trừ các lớp con):
if type(o) is str:
Những điều sau đây cũng hoạt động và có thể hữu ích trong một số trường hợp:
if issubclass(type(o), str):
Xem Hàm dựng sẵn trong Tài liệu tham khảo thư viện Python để biết thông tin liên quan.
Thêm một lưu ý: trong trường hợp này, nếu bạn đang sử dụng Python 2, bạn thực sự có thể muốn sử dụng:
if isinstance(o, basestring):
bởi vì điều này cũng sẽ bắt được các chuỗi Unicode ( unicode
không phải là một lớp con của str
cả hai str
và unicode
là các lớp con của basestring
). Lưu ý rằng basestring
không còn tồn tại trong Python 3, nơi có sự phân tách nghiêm ngặt của chuỗi ( str
) và dữ liệu nhị phân ( bytes
).
Ngoài ra, isinstance
chấp nhận một bộ các lớp. Điều này sẽ trả về True
nếu o
là một thể hiện của bất kỳ lớp con nào trong số (str, unicode)
:
if isinstance(o, (str, unicode)):
type(a) is Object
thì cũng không đúng isinstance(a, Object)
. Tuy nhiên, nếu type(a) is SubClassOfObject
, sau đó type(a) is Object == False
, nhưng isinstance(a, Object) == True
. Đúng?
a is b
có nghĩa là a và b là cùng một thứ, nghĩa là các tham chiếu đến cùng một thực thể trong bộ nhớ. Vì vậy, a
và b
sẽ phải là cùng một lớp, không phải là các lớp con, như với isinstance()
. Xem ví dụ stackoverflow.com/a/133024/1072212
Các nhất cách Pythonic để kiểm tra kiểu của một đối tượng là ... không kiểm tra nó.
Vì Python khuyến khích Gõ vịt , bạn chỉ nên try...except
sử dụng các phương thức của đối tượng theo cách bạn muốn sử dụng chúng. Vì vậy, nếu chức năng của bạn đang tìm kiếm một đối tượng tệp có thể ghi, đừng kiểm tra xem đó có phải là một lớp con không file
, chỉ cần thử sử dụng nó.write()
phương thức !
Tất nhiên, đôi khi những trừu tượng tốt đẹp này bị phá vỡ và isinstance(obj, cls)
là những gì bạn cần. Nhưng sử dụng một cách tiết kiệm.
if hasattr(ob, "write") and callable(ob.write):
Hoặc lưu một số quyền truy cập chính tả ...func = getattr(ob, "write", None)
if callable(func): ...
hasattr
chỉ supresses một AttributeError - Xem: docs.python.org/3.4/library/functions.html#hasattr
isinstance(o, str)
sẽ trả về True
nếu o
là một str
hoặc thuộc loại kế thừa từ str
.
type(o) is str
sẽ trở lại True
nếu và chỉ khi o
là một str. Nó sẽ trả về False
nếu o
thuộc loại kế thừa str
.
isinstance
và type(var) == type('')
không rõ ràng.
Sau khi câu hỏi được hỏi và trả lời, loại gợi ý đã được thêm vào Python . Gợi ý nhập trong Python cho phép các loại được kiểm tra nhưng theo một cách rất khác với các ngôn ngữ được nhập tĩnh. Gợi ý nhập trong Python liên kết các loại đối số dự kiến với các hàm như dữ liệu có thể truy cập thời gian chạy được liên kết với các hàm và điều này cho phép các loại được kiểm tra. Ví dụ về cú pháp gợi ý loại:
def foo(i: int):
return i
foo(5)
foo('oops')
Trong trường hợp này, chúng tôi muốn một lỗi được kích hoạt foo('oops')
vì loại đối số được chú thích là int
. Gợi ý loại đã thêm không gây ra lỗi khi tập lệnh chạy bình thường. Tuy nhiên, nó thêm các thuộc tính cho hàm mô tả các loại dự kiến mà các chương trình khác có thể truy vấn và sử dụng để kiểm tra lỗi loại.
Một trong những chương trình khác có thể được sử dụng để tìm lỗi loại là mypy
:
mypy script.py
script.py:12: error: Argument 1 to "foo" has incompatible type "str"; expected "int"
(Bạn có thể cần cài đặt mypy
từ trình quản lý gói của mình. Tôi không nghĩ rằng nó đi kèm với CPython nhưng dường như có một số mức độ "chính thức".)
Kiểm tra kiểu theo cách này khác với kiểm tra kiểu trong các ngôn ngữ được biên dịch nhập tĩnh. Vì các kiểu là động trong Python, nên việc kiểm tra kiểu phải được thực hiện trong thời gian chạy, điều này gây ra chi phí - ngay cả trên các chương trình chính xác - nếu chúng tôi khẳng định rằng điều đó xảy ra ở mọi cơ hội. Kiểm tra loại rõ ràng cũng có thể hạn chế hơn mức cần thiết và gây ra các lỗi không cần thiết (ví dụ: đối số có thực sự cần phải có list
loại chính xác hay không có gì có thể lặp lại đủ không?).
Mặt trái của việc kiểm tra loại rõ ràng là nó có thể bắt lỗi sớm hơn và đưa ra thông báo lỗi rõ ràng hơn so với gõ vịt. Các yêu cầu chính xác của một loại vịt chỉ có thể được thể hiện bằng tài liệu bên ngoài (hy vọng nó kỹ lưỡng và chính xác) và lỗi từ các loại không tương thích có thể xảy ra ở xa nơi chúng bắt nguồn.
Gợi ý loại của Python có nghĩa là đưa ra một sự thỏa hiệp trong đó các loại có thể được chỉ định và kiểm tra nhưng không có chi phí bổ sung trong quá trình thực thi mã thông thường.
Các typing
biến gói Mời loại có thể được sử dụng trong loại gợi ý để diễn tả những hành vi cần thiết mà không cần loại cụ thể. Ví dụ, nó bao gồm các biến như Iterable
và Callable
cho các gợi ý để chỉ định nhu cầu cho bất kỳ loại nào với các hành vi đó.
Mặc dù gợi ý về kiểu là cách kiểm tra kiểu Pythonic nhiều nhất, nhưng thường thì Pythonic thậm chí còn không kiểm tra kiểu nào cả và dựa vào cách gõ vịt. Gợi ý loại tương đối mới và ban giám khảo vẫn chưa kết thúc khi chúng là giải pháp Pythonic nhất. Một so sánh tương đối không gây tranh cãi nhưng rất chung chung: Gợi ý loại cung cấp một dạng tài liệu có thể được thi hành, cho phép mã tạo ra các lỗi sớm hơn và dễ hiểu hơn, có thể bắt lỗi mà vịt không thể gõ và có thể được kiểm tra tĩnh (trong trường hợp bất thường ý nghĩa nhưng nó vẫn nằm ngoài thời gian chạy). Mặt khác, gõ vịt đã là cách Pythonic trong một thời gian dài, không áp đặt chi phí nhận thức của việc gõ tĩnh, ít dài dòng hơn và sẽ chấp nhận tất cả các loại khả thi và sau đó một số loại.
mypy
là một mô-đun Python sử dụng importlib
để truy cập dữ liệu đó. Cho dù đây là "kiểm tra kiểu tĩnh" là một câu hỏi triết học nhưng nó khác với những gì hầu hết mong đợi vì trình thông dịch ngôn ngữ thông thường và máy móc nhập khẩu có liên quan.
Dưới đây là một ví dụ tại sao gõ vịt là xấu xa mà không biết khi nào nó nguy hiểm. Ví dụ: Đây là mã Python (có thể bỏ qua thụt lề thích hợp), lưu ý rằng tình huống này có thể tránh được bằng cách quan tâm đến các hàm isinstance và hiện tại để đảm bảo rằng khi bạn thực sự cần một con vịt, bạn sẽ không nhận được bom.
class Bomb:
def __init__(self):
""
def talk(self):
self.explode()
def explode(self):
print "BOOM!, The bomb explodes."
class Duck:
def __init__(self):
""
def talk(self):
print "I am a duck, I will not blow up if you ask me to talk."
class Kid:
kids_duck = None
def __init__(self):
print "Kid comes around a corner and asks you for money so he could buy a duck."
def takeDuck(self, duck):
self.kids_duck = duck
print "The kid accepts the duck, and happily skips along"
def doYourThing(self):
print "The kid tries to get the duck to talk"
self.kids_duck.talk()
myKid = Kid()
myBomb = Bomb()
myKid.takeDuck(myBomb)
myKid.doYourThing()
class EvilDuck(Duck)
và ghi đè cuộc nói chuyện (). Hoặc nhiều khả năng, class ChineseCancerDuck(Duck)
với một tác dụng phụ khó chịu không xuất hiện cho đến nhiều năm sau đó. Bạn sẽ tốt hơn nếu chỉ giám sát con bạn (và kiểm tra kỹ lưỡng đồ chơi của nó :)
__file__
thuộc tính (thường được sử dụng để xác định các đối tượng giống như tệp) để có nghĩa khác.
isinstance(o, str)
Tôi nghĩ điều thú vị khi sử dụng một ngôn ngữ động như Python là bạn thực sự không cần phải kiểm tra thứ gì đó như thế.
Tôi sẽ chỉ gọi các phương thức cần thiết trên đối tượng của bạn và bắt một AttributeError
. Sau này, điều này sẽ cho phép bạn gọi các phương thức của mình với các đối tượng khác (dường như không liên quan) để thực hiện các nhiệm vụ khác nhau, chẳng hạn như chế nhạo một đối tượng để thử nghiệm.
Tôi đã sử dụng điều này rất nhiều khi lấy dữ liệu ra khỏi web urllib2.urlopen()
và trả về một tệp giống như đối tượng. Điều này có thể lần lượt có thể được truyền cho hầu hết mọi phương thức đọc từ một tệp, bởi vì nó thực hiện cùng một read()
phương thức như một tệp thực.
Nhưng tôi chắc chắn rằng có một thời gian và địa điểm để sử dụng isinstance()
, nếu không nó có thể sẽ không ở đó :)
Để biết thêm validations loại phức tạp tôi như typeguard 's phương pháp chứng thực dựa trên loại trăn chú thích gợi ý:
from typeguard import check_type
from typing import List
try:
check_type('mylist', [1, 2], List[int])
except TypeError as e:
print(e)
Bạn có thể thực hiện các xác nhận rất phức tạp theo cách rất sạch sẽ và dễ đọc.
check_type('foo', [1, 3.14], List[Union[int, float]])
# vs
isinstance(foo, list) and all(isinstance(a, (int, float)) for a in foo)
Bạn có thể kiểm tra loại biến bằng cách sử dụng __name__ của một loại.
Ví dụ:
>>> a = [1,2,3,4]
>>> b = 1
>>> type(a).__name__
'list'
>>> type(a).__name__ == 'list'
True
>>> type(b).__name__ == 'list'
False
>>> type(b).__name__
'int'
Tới Hugo:
Có thể bạn muốn nói list
đúng hơn array
, nhưng điều đó chỉ ra toàn bộ vấn đề với việc kiểm tra kiểu - bạn không muốn biết liệu đối tượng trong câu hỏi có phải là một danh sách hay không, bạn muốn biết đó là một loại trình tự hay nếu đó là một đối tượng. Vì vậy, hãy cố gắng sử dụng nó như một chuỗi.
Giả sử bạn muốn thêm đối tượng vào một chuỗi hiện có hoặc nếu đó là một chuỗi các đối tượng, hãy thêm tất cả chúng
try:
my_sequence.extend(o)
except TypeError:
my_sequence.append(o)
Một mẹo nhỏ với điều này là nếu bạn đang làm việc với các chuỗi và / hoặc chuỗi các chuỗi - đó là khó khăn, vì một chuỗi thường được coi là một đối tượng, nhưng đó cũng là một chuỗi các ký tự. Tệ hơn thế, vì nó thực sự là một chuỗi các chuỗi có độ dài đơn.
Tôi thường chọn thiết kế API của mình để nó chỉ chấp nhận một giá trị duy nhất hoặc một chuỗi - nó làm cho mọi thứ dễ dàng hơn. Không khó để đặt một [ ]
giá trị xung quanh bạn khi bạn vượt qua nó nếu cần.
(Mặc dù điều này có thể gây ra lỗi với các chuỗi, vì chúng trông giống như (là) chuỗi.)
Một cách đơn giản để kiểm tra loại là so sánh nó với loại mà bạn biết.
>>> a = 1
>>> type(a) == type(1)
True
>>> b = 'abc'
>>> type(b) == type('')
True
Tôi nghĩ rằng cách tốt nhất là gõ tốt các biến của bạn. Bạn có thể làm điều này bằng cách sử dụng thư viện "gõ".
Thí dụ:
from typing import NewType
UserId = NewType ('UserId', int)
some_id = UserId (524313
)
Bạn có thể kiểm tra với dòng dưới đây để kiểm tra loại ký tự nào có giá trị đã cho là:
def chr_type(chrx):
if chrx.isalpha()==True:
return 'alpha'
elif chrx.isdigit()==True:
return 'numeric'
else:
return 'nothing'
chr_type("12)