Python資料型別判斷常遇到的坑

pythontab發表於2017-12-07

python判斷變數資料型別時,建議使用isinstance()方法代替type(). 進行型別檢查首先想到的就是用type(),但是Type在某些特定情況下判斷型別存在問題,今天就來說下type在python型別判斷時的坑。

type()方法

例子: int型別判斷

>>> import types
>>> type(2017)==types.IntType
True


Python2.7中的types型別:

types.BooleanType              #  bool型別
types.BufferType               #  buffer型別
types.BuiltinFunctionType      #  內建函式,比如len()
types.BuiltinMethodType        #  內建方法,指的是類中的方法
types.ClassType                #  類型別
types.CodeType                 #  程式碼塊型別
types.ComplexType              #  複數型別
types.DictProxyType            #  字典代理型別
types.DictType                 #  字典型別
types.DictionaryType           #  字典備用的型別
types.EllipsisType
types.FileType                 #  檔案型別
types.FloatType                #  浮點型別
types.FrameType
types.FunctionType             #  函式型別
types.GeneratorType       
types.GetSetDescriptorType
types.InstanceType             #  例項型別
types.IntType                  #  int型別
types.LambdaType               #  lambda型別
types.ListType                 #  列表型別
types.LongType                 #  long型別
types.MemberDescriptorType
types.MethodType               #  方法型別
types.ModuleType               #  module型別
types.NoneType                 #  None型別
types.NotImplementedType
types.ObjectType               #  object型別
types.SliceTypeh
types.StringType               #  字串型別
types.StringTypes     
types.TracebackType   
types.TupleType                #  元組型別
types.TypeType                 #  型別本身
types.UnboundMethodType
types.UnicodeType    
types.XRangeType


Python3.x中的types型別:

types.BuiltinFunctionType
types.BuiltinMethodType
types.CodeType
types.DynamicClassAttribute
types.FrameType
types.FunctionType
types.GeneratorType
types.GetSetDescriptorType
types.LambdaType
types.MappingProxyType
types.MemberDescriptorType
types.MethodType
types.ModuleType
types.SimpleNamespace
types.TracebackType
types.new_class
types.prepare_class


Python3.x進行了型別的精簡


isinstance方法

isinstance(object, classinfo)

object表示例項,classinfo可以是直接或間接類名、基本型別或者有它們組成的元組。

基本用法

>>> isinstance(1, int)
True
>>> 
>>> isinstance('pythontab.com', (str, int)) # 是其中一種即可
True
>>> isinstance(100, (str, int)) # 是其中一種即可
True


上面type的例子可以表示為:

>>> import types
>>> isinstance(2017,int)
True

那為什麼不推薦使用type進行型別檢查呢?

我們來看一下下面的例子。

import types
class UserInt(int):
    def __init__(self, val=0):
        self.val = int(val)
i = 1
n = UserInt(2)
print(type(i) is type(n))

上面的程式碼輸出:False

這就說明i和n的型別是不一樣的,而實際上UserInt是繼承自int的,所以這個判斷是存在問題的,當我們對Python內建型別進行擴充套件的時候,type返回的結果就不夠準確了。我們再看一個例子。

class ca:
    pass
class cb:
    pass
a = ca()
b = cb()
print (type(a) is type(b))

程式碼的輸出結果: True

注意: 這個例子僅僅針對Python2.x版本, Python3.x版本中會返回Flase,不存在該問題

type比較的結果a和b的型別是一樣的,結果明顯是不準確的。在old-style class中,任意instance的type都是'instance'。所以絕對不能用type來判斷其型別。


另外這個問題又與Python的思想有關,正常情況下不應該編寫程式碼檢查型別的,而應該直接假設被操作的instance具有你希望的屬性,否則丟擲異常。即使需要檢查型別,也應該用isinstance來判斷,這樣你期望型別的subclass也能正常被處理(比如,一個函式需要處理Message型別,那麼它應該也能處理Message的子型別MyMessage,所以應該使用isinstance(arg,Message)這樣來判斷而不是type(arg) == Message來判斷)



結論:


儘量不要使用type()方法,多使用isinstance(),這樣可以減少錯誤。


相關文章