欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python 類與元類的深度挖掘 II【經(jīng)驗(yàn)】

 更新時(shí)間:2016年05月06日 11:54:32   作者:rainyear  
元類在 Python 中屬于比較深層的黑魔法,在一般的日常應(yīng)用中可能并不常用,但理解其背后的原理對(duì)于理解 Python 面向?qū)ο缶幊桃约耙磺薪詾閷?duì)象的理念很有幫助;如果你需要對(duì)類進(jìn)行深度改造,至少要知道從何入手。

  上一篇解決了通過(guò)調(diào)用類對(duì)象生成實(shí)例對(duì)象過(guò)程中可能遇到的命名空間相關(guān)的一些問(wèn)題,這次我們向上回溯一層,看看類對(duì)象本身是如何產(chǎn)生的。

  我們知道 type() 方法可以查看一個(gè)對(duì)象的類型,或者說(shuō)判斷這個(gè)對(duì)象是由那個(gè)類產(chǎn)生的:

  print(type(12))

  print(type('python'))

  class A:

  pass

  print(type(A))

  通過(guò)這段代碼可以看出,類對(duì)象 A 是由type() 產(chǎn)生的,也就是說(shuō) type 也可以用來(lái)產(chǎn)生新的對(duì)象,而且產(chǎn)生的是類對(duì)象,因此它是所有類對(duì)象的類:

  print(type.__doc__)

  type(object_or_name, bases, dict)

  type(object) -> the object's type

  type(name, bases, dict) -> a new type

 

  class 定義類的語(yǔ)法實(shí)際上轉(zhuǎn)化為 type(name, bases, dict),其中 name 參數(shù)為類的名字,bases 為繼承父類的元組,dict 為類的屬性和方法:

class A:
  pass
# 實(shí)際上等于
B = type('A', (), {})

print(A.__name__ == B.__name__)
True

  理論上說(shuō)這就是元類的意義,但從實(shí)際的角度出發(fā)顯然使用 class 語(yǔ)法更方便、合理,而元類的實(shí)際意義則是通過(guò)繼承 type 類來(lái)構(gòu)造一個(gè)新的元類,并進(jìn)行特定的操作以產(chǎn)生具有特定行為的類對(duì)象。這樣看來(lái)它的本質(zhì)與普通的類對(duì)象沒(méi)有差異,只不過(guò)繼承的是 type 類。

  在生成實(shí)例時(shí)是通過(guò)調(diào)用 __init__ 方法進(jìn)行初始化的,而實(shí)際上在此之前會(huì)先調(diào)用 __new__ 方法用于創(chuàng)建實(shí)例,再通過(guò) __init__ 初始化,就好像 __new__ 負(fù)責(zé)聲明變量,而 __init__ 負(fù)責(zé)對(duì)聲明的變量進(jìn)行初始化一樣。這里有一個(gè)規(guī)則是 __new__(cls,) 的返回值必須是 cls 參數(shù)的實(shí)例,否則 __init__ 將不會(huì)觸發(fā),例如在 enum.Enum 的定義中,由于枚舉類型是單例模式,因此在定義 __new__ 的時(shí)候沒(méi)有返回其實(shí)例,也就不會(huì)進(jìn)行初始化:

class Enum:

  def __new__(cls, value):

  print(cls, value)

  return value

  def __init__(self):

  print("Will not be called!")

  e = Enum(1)

   <class '__main__.Enum'> 1

  通常情況下自己定義 __new__ 需要通過(guò)調(diào)用父類的 __new__ 方法創(chuàng)建一個(gè) cls 的實(shí)例,同樣在定義元類的時(shí)候則是調(diào)用上面提到的 type 的用法(因?yàn)樵惱^承自 type):

  

class MetaEnum(type):

  def __new__(metaclass, name, base, attrs):

  print("Metaclass: {}\nName: {}\nParents: {}\nAttributes: {}".format(metaclass, name, base, attrs))

  return super().__new__(metaclass, name, base, attrs)

  class Enum(metaclass=MetaEnum):

  # Python 2.7 中定義元類的方法是使用 __metaclass__ 變量

  # [PEP 3115](https://www.python.org/dev/peps/pep-3115/)

  # 將 Python 3.0 以后語(yǔ)法改為 class Cls(metaclass=Meta)

  test = 0

  Metaclass: 

  Name: Enum

  Parents: ()

  Attributes: {'__qualname__': 'Enum', '__module__': '__main__', 'test': 0}

  此時(shí)我們?cè)賮?lái)看 Enum 的類,已經(jīng)不再是 type 而是其元類 MetaEnum:

  type(Enum)

  __main__.MetaEnum

  除了 __new__ 方法之外,PEP 3115 還定義了 __prepare__ 屬性,用于設(shè)定初始化的命名空間(即 type 的第 3 個(gè)參數(shù)),還是以 enum.Enum 為例,我們需要限制枚舉類型中屬性名稱不得重復(fù)使用,則可以通過(guò)元類限制類的行為:

  # 定義新的字典類,在賦值新的 dict[k] = v 時(shí)

  # 檢查 k 是否重復(fù)

 class _EnumDict(dict):

  def __init__(self):

  super().__init__()

  self.members = []

  def __setitem__(self, k, v):

  if k in self.members:

  raise TypeError("Attempted to reuse key: '{}'".format(k))

  else:

  self.members.append(k)

  super().__setitem__(k, v)

  class MetaEnum(type):

  @classmethod

  def __prepare__(metaclass, cls, bases):

  return _EnumDict()

  def __new__(metaclass, name, base, attrs):

  return super().__new__(metaclass, name, base, attrs)

  class Enum(metaclass=MetaEnum):

  pass

  class Color(Enum):

  try:

  red = 1

  red = 2

  except TypeError:# 這里沒(méi)有使用 as err: 的原因是?

  print("TypeError catched")

  TypeError catched

  Python 中一切皆為對(duì)象,所有的對(duì)象都是某一類的實(shí)例,或是某一元類的實(shí)例,type 是自己的元類也是自己的實(shí)例

相關(guān)文章

  • Python+OpenCV實(shí)現(xiàn)黑白老照片上色功能

    Python+OpenCV實(shí)現(xiàn)黑白老照片上色功能

    我們都知道,有很多經(jīng)典的老照片,受限于那個(gè)時(shí)代的技術(shù),只能以黑白的形式傳世。盡管黑白照片別有一番風(fēng)味,但是彩色照片有時(shí)候能給人更強(qiáng)的代入感。本文就來(lái)用Python和OpenCV實(shí)現(xiàn)老照片上色功能,需要的可以參考一下
    2023-02-02
  • python?numpy庫(kù)中數(shù)組遍歷的方法

    python?numpy庫(kù)中數(shù)組遍歷的方法

    本文主要介紹了python?numpy庫(kù)中數(shù)組遍歷的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • python中的五種異常處理機(jī)制介紹

    python中的五種異常處理機(jī)制介紹

    這篇文章主要介紹了python中的五種異常處理機(jī)制介紹,本文是Learn Python一書(shū)的讀書(shū)筆記,需要的朋友可以參考下
    2014-09-09
  • 淺談python連續(xù)賦值可能引發(fā)的錯(cuò)誤

    淺談python連續(xù)賦值可能引發(fā)的錯(cuò)誤

    今天小編就為大家分享一篇淺談python連續(xù)賦值可能引發(fā)的錯(cuò)誤,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-11-11
  • Python結(jié)合Selenium簡(jiǎn)單實(shí)現(xiàn)Web自動(dòng)化測(cè)試

    Python結(jié)合Selenium簡(jiǎn)單實(shí)現(xiàn)Web自動(dòng)化測(cè)試

    這篇文章是入門(mén)級(jí)別的應(yīng)用Python + Selenium進(jìn)行自動(dòng)化測(cè)試,包括環(huán)境搭建及簡(jiǎn)單的實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • python httpx的具體使用

    python httpx的具體使用

    本文主要介紹了python httpx的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • pandas調(diào)整列的順序以及添加列的實(shí)現(xiàn)

    pandas調(diào)整列的順序以及添加列的實(shí)現(xiàn)

    這篇文章主要介紹了pandas調(diào)整列的順序以及添加列的實(shí)現(xiàn)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-03-03
  • python 多線程實(shí)現(xiàn)多任務(wù)的方法示例

    python 多線程實(shí)現(xiàn)多任務(wù)的方法示例

    本文主要介紹了python 多線程實(shí)現(xiàn)多任務(wù)的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-07-07
  • python判斷字符串以什么結(jié)尾的實(shí)例方法

    python判斷字符串以什么結(jié)尾的實(shí)例方法

    在本篇文章里小編給大家整理了關(guān)于python判斷字符串以什么結(jié)尾的實(shí)例方法 ,需要的朋友們可以學(xué)習(xí)參考下。
    2020-09-09
  • 利用jupyter網(wǎng)頁(yè)版本進(jìn)行python函數(shù)查詢方式

    利用jupyter網(wǎng)頁(yè)版本進(jìn)行python函數(shù)查詢方式

    這篇文章主要介紹了利用jupyter網(wǎng)頁(yè)版本進(jìn)行python函數(shù)查詢方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-04-04

最新評(píng)論