Python中型別最佳判斷方法

諾克大叔發表於2019-03-04

Python在定義變數的時候不用指明具體的的型別,直譯器會在執行的時候會自動檢查變數的型別,並根據需要進行隱式的型別轉化,因為Python是動態語言,所以一般情況下是不推薦進行型別轉化的。

比如進行"+"操作時,如果加號兩邊是資料就進行加法操作,如果兩邊是字串就進行字串連線操作,如果兩邊是列表就進行合併操作,甚至可以進行復數的運算。

直譯器會在執行時根據兩邊的變數的型別呼叫不同的內部方法。當加號兩邊的變數型別不一樣的時候,又不能進行型別轉化,就會丟擲TypeError的異常。

types模組從Python2到Python3的變化

在實際的開發中,為了提高程式碼的健壯性,我們還是需要進行型別檢查的。而進行型別檢查首先想到的就是用types(),比如使用types判斷一個int型別:

Source Code:

#!/usr/bin/env python2.6
#Author: nock.chen
from types import *
mylist = ['nock', 100, '100', 'IT']

def delete(mylist, item):	
	if type(item) is IntType:
		mylist.remove(item)
						
delete(mylist, 100)
print(mylist)
複製程式碼

Result:

['nock', '100', 'IT']
複製程式碼

我們在types模組中可以找到一些常用的型別,在2.6.9中顯示的結果:

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             #  Ellipsis型別
types.FileType                 #  檔案型別
types.FloatType                #  浮點型別
types.FrameType                #  框架物件的型別
types.FunctionType             #  函式型別
types.GeneratorType            #  通過呼叫生成器函式生成的generator-iterator物件型別
types.GetSetDescriptorType     #  用PyGetSetDef(如FrameType)在擴充套件模組中定義的物件的型別
types.InstanceType             #  例項型別
types.IntType                  #  int型別
types.LambdaType               #  lambda型別
types.ListType                 #  列表型別
types.LongType                 #  long型別
types.MemberDescriptorType     #  在擴充套件模組中定義的物件型別,包括PyMemberDef,如datetime.timedelta.days        
types.MethodType               #  方法型別
types.ModuleType               #  module型別
types.NoneType                 #  None型別
types.NotImplementedType       #  NotImplemented的型別
types.ObjectType               #  object型別
types.SliceType                #  slice()返回的物件型別
types.StringType               #  字串型別
types.StringTypes              #  一個包含StringType和UnicodeType的序列,用於方便對任何字串物件進行檢查。
types.TracebackType            #  在sys.exc_traceback中發現的traceback物件的型別。
types.TupleType                #  元組型別
types.TypeType                 #  型別本身
types.UnboundMethodType        #  另一個名字for MethodType
types.UnicodeType              #  Unicode字元字串的型別(例如,u ' spam)
types.XRangeType               #  xrange()返回的範圍物件的型別
複製程式碼

官網介紹:https://docs.python.org/2/library/types.html

到了Python3版本,types模組方法已經明顯減少了很多,具體如下:

types.BuiltinFunctionType               
types.BuiltinMethodType         # 內建函式的型別,如len()或sys.exit(),以及內建類的方法。(這裡,“內建”的意思是“用C寫”。)
types.CodeType                  # 通過compile()返回的程式碼物件型別。
types.DynamicClassAttribute
types.FrameType                 # 框架物件的型別,如在tb中發現的。tb_frame如果tb是一個traceback物件。
types.FunctionType
types.GeneratorType             # 由生成器函式建立的generator - iterator物件型別。
types.GetSetDescriptorType      # 用PyGetSetDef(如FrameType)在擴充套件模組中定義的物件的型別。
types.LambdaType                # 由lambda表示式建立的使用者定義函式和函式的型別。
types.MappingProxyType
types.MemberDescriptorType
types.MethodType                # 使用者定義類例項的方法型別。
types.ModuleType
types.SimpleNamespace
types.TracebackType             # traceback物件的型別,如sys.exc_info()
types.new_class
types.prepare_class
複製程式碼

官網介紹:https://docs.python.org/3/library/types.html#module-types

不推薦使用type檢查型別

從上面的Python2到Python3的版本升級過程中,types模組方法有所減少。如果使用type方法也會存在如下問題:

Python中型別最佳判斷方法

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

Python中型別最佳判斷方法
type比較的結果a和b的型別是一樣的,結果明顯是不準確的。這種古典類的例項,type返回的結果都是一樣的,而這樣的結果不是我們想要的。對於內建的基本型別來說,使用tpye來檢查是沒有問題的, 可是當應用到其他場合的時候,type就顯得不可靠了。

這個時候我們就需要使用內建函式isinstance來進行型別檢查,示例如下:

isinstance(object, class_or_type_or_tuple)
複製程式碼

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

nock:ucode nock$ python3
Python 3.5.1 (default, Dec 26 2015, 18:08:53) 
[GCC 4.2.1 Compatible Apple LLVM 7.0.2 (clang-700.1.81)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> isinstance(2, float)
False
>>> isinstance(2, int)
True
>>> isinstance((2, 3), list)
False
>>> isinstance((2, 3), tuple)
True
>>> isinstance({'name': 'nock'}, tuple)
False
>>> isinstance({'name': 'nock'}, dict)
True
>>> isinstance([1, 100, 101], (str, list, tuple))
True
>>> isinstance(2 ** 31, dict)
False
>>> isinstance(2 ** 31, long)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'long' is not defined
>>> isinstance(2 ** 31, int)
True
複製程式碼

Python2有為非浮點數準備的intlong型別。int型別的最大值不能超過sys.maxint,而且這個最大值是平臺相關的。可以通過在數字的末尾附上一個L來定義長整型,顯然,它比int型別表示的數字範圍更大。在Python3裡,只有一種整數型別int,大多數情況下,它很像Python2裡的長整型。由於已經不存在兩種型別的整數,所以就沒有必要使用特殊的語法去區別他們, 進一步閱讀:PEP 237

最後在Python中型別的判斷你最好的方法是利用內建函式isinstance完成是最佳體驗。

官網介紹:https://docs.python.org/3/library/functions.html#isinstance

Python中型別最佳判斷方法

相關文章