最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

在Python 3中實(shí)現(xiàn)類型檢查器的簡(jiǎn)單方法

 更新時(shí)間:2015年07月03日 16:00:39   投稿:goldensun  
這篇文章主要介紹了在Python 3中實(shí)現(xiàn)類型檢查器的簡(jiǎn)單方法,包括對(duì)函數(shù)注解這個(gè)新特性的介紹,需要的朋友可以參考下

示例函數(shù)

為了開(kāi)發(fā)類型檢查器,我們需要一個(gè)簡(jiǎn)單的函數(shù)對(duì)其進(jìn)行實(shí)驗(yàn)。歐幾里得算法就是一個(gè)完美的例子:
 

def gcd(a, b):
  
'''Return the greatest common divisor of a and b.'''
  a = abs(a)
  b = abs(b)
  if a < b:
    a, b = b, a
  while b != 0:
    a, b = b, a % b
  return a

在上面的示例中,參數(shù) a 和 b 以及返回值應(yīng)該是 int 類型的。預(yù)期的類型將會(huì)以函數(shù)注解的形式來(lái)表達(dá),函數(shù)注解是 Python 3 的一個(gè)新特性。接下來(lái),類型檢查機(jī)制將會(huì)以一個(gè)裝飾器的形式實(shí)現(xiàn),注解版本的第一行代碼是:
 

def gcd(a: int, b: int) -> int:

使用“gcd.__annotations__”可以獲得一個(gè)包含注解的字典:
 

>>> gcd.__annotations__
{'return': <class 'int'>, 'b': <class 'int'>, 'a': <class 'int'>}
>>> gcd.__annotations__['a']
<class 'int'>

需要注意的是,返回值的注解存儲(chǔ)在鍵“return”下。這是有可能的,因?yàn)椤皉eturn”是一個(gè)關(guān)鍵字,所以不能用作一個(gè)有效的參數(shù)名。
檢查返回值類型

返回值注解存儲(chǔ)在字典“__annotations__”中的“return”鍵下。我們將使用這個(gè)值來(lái)檢查返回值(假設(shè)注解存在)。我們將參數(shù)傳遞給原始函數(shù),如果存在注解,我們將通過(guò)注解中的值來(lái)驗(yàn)證其類型:
 

def typecheck(f):
  def wrapper(*args, **kwargs):
    result = f(*args, **kwargs)
    return_type = f.__annotations__.get('return', None)
    if return_type and not isinstance(result, return_type):
      raise RuntimeError("{} should return {}".format(f.__name__, return_type.__name__))
    return result
  return wrapper

我們可以用“a”替換函數(shù)gcd的返回值來(lái)測(cè)試上面的代碼:

 
Traceback (most recent call last):
 File "typechecker.py", line 9, in <module>
  gcd(1, 2)
 File "typechecker.py", line 5, in wrapper
  raise RuntimeError("{} should return {}".format(f.__name__, return_type.__name__))
RuntimeError: gcd should return int

由上面的結(jié)果可知,確實(shí)檢查了返回值的類型。
檢查參數(shù)類型

函數(shù)的參數(shù)存在于關(guān)聯(lián)代碼對(duì)象的“co_varnames”屬性中,在我們的例子中是“gcd.__code__.co_varnames”。元組包含了所有局部變量的名稱,并且該元組以參數(shù)開(kāi)始,參數(shù)數(shù)量存儲(chǔ)在“co_nlocals”中。我們需要遍歷包括索引在內(nèi)的所有變量,并從參數(shù)“args”中獲取參數(shù)值,最后對(duì)其進(jìn)行類型檢查。

得到了下面的代碼:
 

def typecheck(f):
  def wrapper(*args, **kwargs):
    for i, arg in enumerate(args[:f.__code__.co_nlocals]):
      name = f.__code__.co_varnames[i]
      expected_type = f.__annotations__.get(name, None)
      if expected_type and not isinstance(arg, expected_type):
        raise RuntimeError("{} should be of type {}; {} specified".format(name, expected_type.__name__, type(arg).__name__))
    result = f(*args, **kwargs)
    return_type = f.__annotations__.get('return', None)
    if return_type and not isinstance(result, return_type):
      raise RuntimeError("{} should return {}".format(f.__name__, return_type.__name__))
    return result
  return wrapper

在上面的循環(huán)中,i是數(shù)組args中參數(shù)的以0起始的索引,arg是包含其值的字符串??梢岳谩癴.__code__.co_varnames[i]”讀取到參數(shù)的名稱。類型檢查代碼與返回值類型檢查完全一樣(包括錯(cuò)誤消息的異常)。

為了對(duì)關(guān)鍵字參數(shù)進(jìn)行類型檢查,我們需要遍歷參數(shù)kwargs。此時(shí)的類型檢查幾乎與第一個(gè)循環(huán)中相同:
 

for name, arg in kwargs.items():
  expected_type = f.__annotations__.get(name, None)
  if expected_type and not isinstance(arg, expected_type):
    raise RuntimeError("{} should be of type {}; {} specified".format(name, expected_type.__name__, type(arg).__name__))

得到的裝飾器代碼如下:
 

def typecheck(f):
  def wrapper(*args, **kwargs):
    for i, arg in enumerate(args[:f.__code__.co_nlocals]):
      name = f.__code__.co_varnames[i]
      expected_type = f.__annotations__.get(name, None)
      if expected_type and not isinstance(arg, expected_type):
        raise RuntimeError("{} should be of type {}; {} specified".format(name, expected_type.__name__, type(arg).__name__))
    for name, arg in kwargs.items():
      expected_type = f.__annotations__.get(name, None)
      if expected_type and not isinstance(arg, expected_type):
        raise RuntimeError("{} should be of type {}; {} specified".format(name, expected_type.__name__, type(arg).__name__))
    result = f(*args, **kwargs)
    return_type = f.__annotations__.get('return', None)
    if return_type and not isinstance(result, return_type):
      raise RuntimeError("{} should return {}".format(f.__name__, return_type.__name__))
    return result
  return wrapper

將類型檢查代碼寫(xiě)成一個(gè)函數(shù)將會(huì)使代碼更加清晰。為了簡(jiǎn)化代碼,我們修改錯(cuò)誤信息,而當(dāng)返回值是無(wú)效的類型時(shí),將會(huì)使用到這些錯(cuò)誤信息。我們也可以利用 functools 模塊中的 wraps 方法,將包裝函數(shù)的一些屬性復(fù)制到 wrapper 中(這使得 wrapper 看起來(lái)更像原來(lái)的函數(shù)):
 

def typecheck(f):
  def do_typecheck(name, arg):
    expected_type = f.__annotations__.get(name, None)
    if expected_type and not isinstance(arg, expected_type):
      raise RuntimeError("{} should be of type {} instead of {}".format(name, expected_type.__name__, type(arg).__name__))
 
  @functools.wraps(f)
  def wrapper(*args, **kwargs):
    for i, arg in enumerate(args[:f.__code__.co_nlocals]):
      do_typecheck(f.__code__.co_varnames[i], arg)
    for name, arg in kwargs.items():
      do_typecheck(name, arg)
 
    result = f(*args, **kwargs)
 
    do_typecheck('return', result)
    return result
  return wrapper

結(jié)論

注解是 Python 3 中的一個(gè)新元素,本文例子中的使用方法很普通,你也可以想象很多特定領(lǐng)域的應(yīng)用。雖然上面的實(shí)現(xiàn)代碼并不能滿足實(shí)際產(chǎn)品要求,但它的目的本來(lái)就是用作概念驗(yàn)證??梢詫?duì)其進(jìn)行以下改善:

  •     處理額外的參數(shù)( args 中意想不到的項(xiàng)目)
  •     默認(rèn)值類型檢查
  •     支持多個(gè)類型
  •     支持模板類型(例如,int 型列表)

相關(guān)文章

  • Python?PyQt5?開(kāi)啟線程防止界面卡死閃退問(wèn)題解決

    Python?PyQt5?開(kāi)啟線程防止界面卡死閃退問(wèn)題解決

    這篇文章主要介紹了Python?PyQt5?開(kāi)啟線程避免界面卡死閃退,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • matplotlib之多邊形選區(qū)(PolygonSelector)的使用

    matplotlib之多邊形選區(qū)(PolygonSelector)的使用

    這篇文章主要介紹了matplotlib之多邊形選區(qū)(PolygonSelector)的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • 詳解使用Pytorch Geometric實(shí)現(xiàn)GraphSAGE模型

    詳解使用Pytorch Geometric實(shí)現(xiàn)GraphSAGE模型

    這篇文章主要為大家介紹了詳解使用Pytorch Geometric實(shí)現(xiàn)GraphSAGE模型示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • 從基礎(chǔ)到進(jìn)階帶你玩轉(zhuǎn)Python中的JSON

    從基礎(chǔ)到進(jìn)階帶你玩轉(zhuǎn)Python中的JSON

    JSON是一種輕量級(jí)的數(shù)據(jù)交換格式,在Python中處理JSON數(shù)據(jù)是日常開(kāi)發(fā)中的常見(jiàn)任務(wù)之一,本文將詳細(xì)介紹如何在Python中處理JSON對(duì)象,需要的可以參考下
    2024-12-12
  • 關(guān)于Python中compile() 函數(shù)簡(jiǎn)單實(shí)用示例詳解

    關(guān)于Python中compile() 函數(shù)簡(jiǎn)單實(shí)用示例詳解

    這篇文章主要介紹了關(guān)于compile() 函數(shù)簡(jiǎn)單實(shí)用示例,compile() 函數(shù)將一個(gè)字符串編譯為字節(jié)代碼,compile將代碼編譯為代碼對(duì)象,應(yīng)用在代碼中可以提高效率,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05
  • Python讀取中文路徑出現(xiàn)亂碼問(wèn)題的解決方案

    Python讀取中文路徑出現(xiàn)亂碼問(wèn)題的解決方案

    小編在使用opencv讀取帶有中文路徑的圖片時(shí),發(fā)現(xiàn)會(huì)出現(xiàn)亂碼的情況,當(dāng)讀取的文件路徑出現(xiàn)中文時(shí),(文件夾名為中文或者文件為中文)出現(xiàn)錯(cuò)誤,所以本文給大家介紹了Python讀取中文路徑出現(xiàn)亂碼問(wèn)題的解決方案,需要的朋友可以參考下
    2024-06-06
  • Numpy實(shí)現(xiàn)卷積神經(jīng)網(wǎng)絡(luò)(CNN)的示例

    Numpy實(shí)現(xiàn)卷積神經(jīng)網(wǎng)絡(luò)(CNN)的示例

    這篇文章主要介紹了Numpy實(shí)現(xiàn)卷積神經(jīng)網(wǎng)絡(luò)(CNN)的示例,幫助大家更好的理解和使用Numpy,感興趣的朋友可以了解下
    2020-10-10
  • python用函數(shù)創(chuàng)造字典的實(shí)例講解

    python用函數(shù)創(chuàng)造字典的實(shí)例講解

    在本篇文章里小編給大家整理的是一篇關(guān)于python用函數(shù)創(chuàng)造字典的實(shí)例講解內(nèi)容,有需要的朋友們可以學(xué)習(xí)參考下。
    2021-06-06
  • 如何高效使用Python字典的方法詳解

    如何高效使用Python字典的方法詳解

    Dictionary 是 Python 的內(nèi)置數(shù)據(jù)類型之一,它定義了鍵和值之間一對(duì)一的關(guān)系。下面這篇文章主要給大家介紹了關(guān)于如何高效使用Python字典的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-08-08
  • 用python給csv里的數(shù)據(jù)排序的具體代碼

    用python給csv里的數(shù)據(jù)排序的具體代碼

    在本文里小編給大家分享的是關(guān)于用python給csv里的數(shù)據(jù)排序的具體代碼內(nèi)容,需要的朋友們可以學(xué)習(xí)下。
    2020-07-07

最新評(píng)論

三门县| 长春市| 调兵山市| 禹州市| 大邑县| 文登市| 隆安县| 勐海县| 安顺市| 富蕴县| 河北省| 出国| 阿坝| 延安市| 吉木乃县| 铁岭县| 德惠市| 临潭县| 繁峙县| 大荔县| 海盐县| 澎湖县| 金川县| 烟台市| 邯郸县| 新安县| 孝义市| 眉山市| 册亨县| 柳林县| 宁陵县| 玉溪市| 岳阳县| 贞丰县| 额济纳旗| 博罗县| 湾仔区| 仪征市| 若羌县| 安仁县| 阿克苏市|