這兩個代碼片斷之間有什麼區別? 使用type()
: html
import types if type(a) is types.DictType: do_something() if type(b) in types.StringTypes: do_something_else()
使用isinstance()
: python
if isinstance(a, dict): do_something() if isinstance(b, str) or isinstance(b, unicode): do_something_else()
後者是首選,由於它將正確處理子類。 實際上,您的示例能夠更容易編寫,由於isinstance()
的第二個參數多是一個元組: 設計模式
if isinstance(b, (str, unicode)): do_something_else()
或者,使用basestring
抽象類: app
if isinstance(b, basestring): do_something_else()
這是一個例子,其中isinstance
實現了type
不能的東西: ide
class Vehicle: pass class Truck(Vehicle): pass
在這種狀況下,卡車對象是一輛車,但你會獲得這個: 函數
isinstance(Vehicle(), Vehicle) # returns True type(Vehicle()) == Vehicle # returns True isinstance(Truck(), Vehicle) # returns True type(Truck()) == Vehicle # returns False, and this probably won't be what you want.
換句話說,對於子類, isinstance
也是如此。 測試
另請參閱: 如何在Python中比較對象的類型? this
根據python文檔,這裏有一個聲明: spa
8.15。 types - 內置類型的名稱
從Python 2.2開始,內置的工廠函數(如
int()
和str()
也是相應類型的名稱。 .net
因此isinstance()
應優先於type()
。
總結其餘(已經很好!)答案的內容, isinstance
迎合繼承(派生類的實例也是基類的實例),而檢查type
相等則不須要(它須要類型的標識和拒絕子類型的實例,AKA子類)。
一般,在Python中,你但願你的代碼支持繼承,固然(由於繼承很是方便,使用你的代碼來阻止使用它的代碼會很糟糕!)因此isinstance
比檢查type
s的標識要糟糕,由於它無縫地支持繼承。
並非由於isinstance
是好的 ,請注意 - 它比檢查類型的相等性更糟糕 。 正常的,Pythonic,首選解決方案几乎老是「鴨子打字」:嘗試使用該參數,就好像它是某種指望的類型同樣,在try
/ except
語句中執行它,捕獲可能出現的全部異常,若是參數實際上不是那種類型(或任何其餘類型很好地模仿它;-),並在except
子句中,嘗試其餘東西(使用參數「好像」它是其餘類型)。
可是, basestring
是一個很是特殊的狀況 - 內置類型只存在讓你使用isinstance
( str
和unicode
子類basestring
)。 字符串是序列(你能夠循環它們,索引它們,切片它們......),但你一般但願將它們視爲「標量」類型 - 它有點不方便(可是一個至關頻繁的用例)來處理各類類型的字符串(也許是其餘標量類型,即你沒法循環的那些)單向,全部容器(列表,集合,dicts,......)以另外一種方式, basestring
plus isinstance
幫助你作到這一點 - 總體結構這個成語是這樣的:
if isinstance(x, basestring) return treatasscalar(x) try: return treatasiter(iter(x)) except TypeError: return treatasscalar(x)
你能夠說basestring
是一個抽象基類 (「ABC」) - 它沒有爲子類提供具體的功能,而是做爲「標記」存在,主要用於isinstance
。 這個概念在Python中顯然是一個不斷增加的概念,由於引入它的歸納的PEP 3119被接受而且已經從Python 2.6和3.0開始實現。
PEP清楚地代表,雖然ABCs常常能夠替代鴨子打字,但一般沒有很大的壓力(見這裏 )。 然而,在最近的Python版本中實現的ABCs提供了額外的好處: isinstance
(和issubclass
)如今不只僅意味着「[派生類的一個實例]」(特別是,任何類均可以用ABC「註冊」,以便它將顯示爲子類,其實例顯示爲ABC的實例; 和ABC還能夠經過模板方法設計模式應用程序以很是天然的方式爲實際的子類提供額外的便利(有關TM DP的更多信息,請參見此處和[ 此處 [[第II部分]],通常而言,特別是在Python中,獨立於ABCs) 。
有關Python 2.6中提供的ABC支持的基礎機制,請參閱此處 ; 對於他們的3.1版本,很是類似,請看這裏 。 在這兩個版本中,標準庫模塊集合 (這是3.1版本 - 很是類似的2.6版本,請參見此處 )提供了幾個有用的ABC。
爲了這個答案的目的,保留關於ABCs的關鍵(除了能夠說更天然的TM DP功能放置,與混合類的經典Python替代方案,如UserDict.DictMixin ),它們是isinstance
(和issubclass
)比之前更加有吸引力和廣泛(在Python 2.6和以前)(在2.5及以前),所以,相比之下,使檢查類型相等在最近的Python版本中比之前更糟糕。
Python中
isinstance()
和type()
之間的區別?
使用類型檢查
isinstance(obj, Base)
容許子類的實例和多個可能的基礎:
isinstance(obj, (Base1, Base2))
而使用。進行類型檢查
type(obj) is Base
僅支持引用的類型。
一點題外話, is
極可能比更合適
type(obj) == Base
由於班級是單身人士。
在Python中,一般您但願容許任何類型的參數,按預期處理它,若是對象沒有按預期運行,它將引起適當的錯誤。 這被稱爲多態,也稱爲鴨子打字。
def function_of_duck(duck): duck.quack() duck.swim()
若是上面的代碼有效,咱們能夠假設咱們的論點是一個鴨子。 所以咱們能夠傳遞其餘東西是鴨子的實際子類型:
function_of_duck(mallard)
或者像鴨子同樣工做:
function_of_duck(object_that_quacks_and_swims_like_a_duck)
咱們的代碼仍然有效。
可是,在某些狀況下須要明確地進行類型檢查。 也許你對不一樣的對象類型有明智的關係。 例如,Pandas Dataframe對象能夠從dicts 或記錄構造。 在這種狀況下,您的代碼須要知道它所得到的參數類型,以便它能夠正確處理它。
那麼,回答這個問題:
isinstance()
和type()
之間的區別? 請容許我證實一下差別:
type
假設您的函數得到某種類型的參數(構造函數的常見用例),則須要確保某種行爲。 若是你檢查這樣的類型:
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')
若是咱們嘗試傳入一個dict的子類dict
(咱們應該可以,若是咱們指望咱們的代碼遵循Liskov Substitution的原則,那些子類型能夠代替類型)咱們的代碼會破壞!:
from collections import OrderedDict foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))
提出錯誤!
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in foo ValueError: argument must be a dict
isinstance
但若是咱們使用isinstance
,咱們能夠支持Liskov Substitution!:
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')]))
返回OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])
事實上,咱們能夠作得更好。 collections
提供了抽象基類,能夠爲各類類型強制實施最小協議。 在咱們的例子中,若是咱們只指望Mapping
協議,咱們能夠執行如下操做,而且咱們的代碼變得更加靈活:
from collections import Mapping def foo(a_dict): if not isinstance(a_dict, Mapping): raise ValueError('argument must be a dict') return a_dict
應該注意,類型能夠用於使用
type(obj) in (A, B, C)
來檢查多個類
是的,您能夠測試類型是否相等,可是除了上述內容以外,使用多個基數來控制流,除非您特別只容許這些類型:
isinstance(obj, (A, B, C))
另外一個區別是, isinstance
支持能夠替代父類的子類,而不會破壞程序,這個屬性稱爲Liskov替換。
可是,更好的是,反轉你的依賴關係而且根本不檢查特定的類型。
所以,既然咱們要支持代子類,在大多數狀況下,咱們要避免進行類型檢查與type
,喜歡與類型檢查isinstance
-除非你真的須要知道確切類的實例。