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

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

 更新時(shí)間:2016年05月06日 11:37:46   作者:rainyear  
super() 方法解決了類->實(shí)例實(shí)踐過(guò)程中關(guān)于命名空間的一些問(wèn)題,而關(guān)于生成對(duì)象的流程,我們知道初始化實(shí)例是通過(guò)類的 __init__() 方法完成的,在此之前可能涉及到一些其它的準(zhǔn)備工作,包括接下來(lái)提到的 mro() 方法以及關(guān)鍵的元類->類的過(guò)程

  上一篇介紹了 Python 枚舉類型的標(biāo)準(zhǔn)庫(kù),除了考慮到其實(shí)用性,還有一個(gè)重要的原因是其實(shí)現(xiàn)過(guò)程是一個(gè)非常好的學(xué)習(xí)、理解 Python 類與元類的例子。因此接下來(lái)兩篇就以此為例,深入挖掘 Python 中類與元類背后的機(jī)制。

  翻開(kāi)任何一本 Python 教程,你一定可以在某個(gè)位置看到下面這兩句話:

  Python 中一切皆為對(duì)象(Everything in Python is an object);

  Python 是一種面向?qū)ο缶幊?Object Oriented Programming, OOP)的語(yǔ)言。

  雖然在上面兩句話的語(yǔ)境中,對(duì)象(Object)的含義可能稍有不同,但可以肯定的是對(duì)象在 Python 中具有非常重要的意義,也是我們接下來(lái)將要討論的所有內(nèi)容的基礎(chǔ)。那么,對(duì)象到底是什么?

  對(duì)象(Object)

  對(duì)象是 Python 中對(duì)數(shù)據(jù)的一種抽象,Python 程序中所有數(shù)據(jù)都是通過(guò)對(duì)象或?qū)ο笾g的關(guān)系來(lái)表示的。[ref: Data Model]

  港臺(tái)將 Object 翻譯為“物件”,可以將其看作是一個(gè)盛有數(shù)據(jù)的盒子,只不過(guò)除了純粹的數(shù)據(jù)之外還有其它有用的屬性信息,在 Python 中,所有的對(duì)象都具有id、type、value三個(gè)屬性:

+---------------+
|  |
| Python Object |
|  |
+------+--------+
| ID | |
+---------------+
| Type | |
+---------------+
| Value| |
+---------------+

  其中 id 代表內(nèi)存地址,可以通過(guò)內(nèi)置函數(shù) id() 查看,而 type 表示對(duì)象的類別,不同的類別意味著該對(duì)象擁有的屬性和方法等,可以通過(guò) type() 方法查看:

 def who(obj):

  print(id(obj), type(obj))

  who(1)

  who(None)

  who(who)

  4515088368 

  4514812344 

  4542646064 

  對(duì)象作為 Python 中的基本單位,可以被創(chuàng)建、命名或刪除。Python 中一般不需要手動(dòng)刪除對(duì)象,其垃圾回收機(jī)制會(huì)自動(dòng)處理不再使用的對(duì)象,當(dāng)然如果需要,也可以使用 del 語(yǔ)句刪除某個(gè)變量;所謂命名則是指給對(duì)象貼上一個(gè)名字標(biāo)簽,方便使用,也就是聲明或賦值變量;接下來(lái)我們重點(diǎn)來(lái)看如何創(chuàng)建一個(gè)對(duì)象。對(duì)于一些 Python 內(nèi)置類型的對(duì)象,通??梢允褂锰囟ǖ恼Z(yǔ)法生成,例如數(shù)字直接使用阿拉伯?dāng)?shù)字字面量,字符串使用引號(hào) '',列表使用 [],字典使用 {} ,函數(shù)使用 def 語(yǔ)法等,這些對(duì)象的類型都是 Python 內(nèi)置的,那我們能不能創(chuàng)建其它類型的對(duì)象呢?

  類與實(shí)例

  既然說(shuō) Python 是面向?qū)ο缶幊陶Z(yǔ)言,也就允許用戶自己創(chuàng)建對(duì)象,通常使用 class 語(yǔ)句,與其它對(duì)象不同的是,class 定義的對(duì)象(稱之為類)可以用于產(chǎn)生新的對(duì)象(稱之為實(shí)例):

  

class A:

  pass

  a = A()

  who(A)

  who(a)

  140477703944616 

  4542635424 

  上面的例子中 A 是我們創(chuàng)建的一個(gè)新的類,而通過(guò)調(diào)用 A() 可以獲得一個(gè) A 類型的實(shí)例對(duì)象,我們將其賦值為 a,也就是說(shuō)我們成功創(chuàng)建了一個(gè)與所有內(nèi)置對(duì)象類型不同的對(duì)象 a,它的類型為 __main__.A!至此我們可以將 Python 中一切的對(duì)象分為兩種:

  可以用來(lái)生成新對(duì)象的類,包括內(nèi)置的 int、str 以及自己定義的 A 等;

  由類生成的實(shí)例對(duì)象,包括內(nèi)置類型的數(shù)字、字符串以及自己定義的類型為 __main__.A 的 a。

  單純從概念上理解這兩種對(duì)象沒(méi)有任何問(wèn)題,但是這里要討論的是在實(shí)踐中不得不考慮的一些細(xì)節(jié)性問(wèn)題:

  需要一些方便的機(jī)制來(lái)實(shí)現(xiàn)面向?qū)ο缶幊讨械睦^承、重載等特性;

  需要一些固定的流程讓我們可以在生成實(shí)例化對(duì)象的過(guò)程中執(zhí)行一些特定的操作;

  這兩個(gè)問(wèn)題主要關(guān)于類的一些特殊的操作,也就是這一篇后面的主要內(nèi)容。如果再回顧一下開(kāi)頭提到的兩句話,你可能會(huì)想到,既然類本身也是對(duì)象,那它們又是怎樣生成的?這就是后一篇將主要討論的問(wèn)題:用于生成類對(duì)象的類,即元類(Metaclass)。

  super, mro()

  0x00 Python 之禪中提到的最后一條,命名空間(namespace)是個(gè)絕妙的理念,類或?qū)ο笤?Python 中就承擔(dān)了一部分命名空間的作用。比如說(shuō)某些特定的方法或?qū)傩灾挥刑囟愋偷膶?duì)象才有,不同類型對(duì)象的屬性和方法盡管名字可能相同,但由于隸屬不同的命名空間,其值可能完全不同。在實(shí)現(xiàn)類的繼承與重載等特性時(shí)同樣需要考慮命名空間的問(wèn)題,以枚舉類型的實(shí)現(xiàn)為例,我們需要保證枚舉對(duì)象的屬性名稱不能有重復(fù),因此我們需要繼承內(nèi)置的 dict 類:

 

 class _EnumDict(dict):

  def __init__(self):

  dict.__init__(self)

  self._member_names = []

  def keys(self):

  keys = dict.keys(self)

  return list(filter(lambda k: k.isupper(), keys))

  ed = _EnumDict()

  ed['RED'] = 1

  ed['red'] = 2

  print(ed, ed.keys())

  {'RED': 1, 'red': 2} ['RED']

  在上面的例子中 _EnumDict 重載同時(shí)調(diào)用了父類 dict 的一些方法,上面的寫(xiě)法在語(yǔ)法上是沒(méi)有錯(cuò)誤的,但是如果我們要改變 _EnumDict 的父類,不再是繼承自 dict,則必須手動(dòng)修改所有方法中 dict.method(self) 的調(diào)用形式,這樣就不是一個(gè)好的實(shí)踐方案了。為了解決這一問(wèn)題,Python 提供了一個(gè)內(nèi)置函數(shù) super():

  

print(super.__doc__)

  super() -> same as super(__class__, )

  super(type) -> unbound super object

  super(type, obj) -> bound super object; requires isinstance(obj, type)

  super(type, type2) -> bound super object; requires issubclass(type2, type)

  Typical use to call a cooperative superclass method:

  class C(B):

  def meth(self, arg):

  super().meth(arg)

  This works for class methods too:

  class C(B):

  @classmethod

  def cmeth(cls, arg):

  super().cmeth(arg)

  我最初只是把 super() 當(dāng)做指向父類對(duì)象的指針,但實(shí)際上它可以提供更多功能:給定一個(gè)對(duì)象及其子類(這里對(duì)象要求至少是類對(duì)象,而子類可以是實(shí)例對(duì)象),從該對(duì)象父類的命名空間開(kāi)始搜索對(duì)應(yīng)的方法。

  以下面的代碼為例:

 class A(object):

  def method(self):

  who(self)

  print("A.method")

  class B(A):

  def method(self):

  who(self)

  print("B.method")

  class C(B):

  def method(self):

  who(self)

  print("C.method")

  class D(C):

  def __init__(self):

  super().method()

  super(__class__, self).method()

  super(C, self).method() # calling C's parent's method

  super(B, self).method() # calling B's parent's method

  super(B, C()).method() # calling B's parent's method with instance of C

  d = D()

  print("\nInstance of D:")

  who(d)

  4542787992 

  C.method

  4542787992 

  C.method

  4542787992 

  B.method

  4542787992 

  A.method

  4542788048 

  A.method

  Instance of D:

  4542787992 

  當(dāng)然我們也可以在外部使用 super() 方法,只是不能再用缺省參數(shù)的形式,因?yàn)樵谕獠康拿臻g中不再存在 __class__ self:

 super(D, d).method() # calling D's parent's method with instance d

  4542787992 

  C.method

  上面的例子可以用下圖來(lái)描述:

+----------+
| A |
+----------+
| method() <---------------+ super(B,self)
+----------+  |
    |
+----------+  +----------+
| B |  | D |
+----------+ super(C,self) +----------+
| method() <---------------+ method() |
+----------+  +----------+
    |
+----------+  |
| C |  |
+----------+  | super(D,self)
| method() <---------------+
+----------+

   可以認(rèn)為 super() 方法通過(guò)向父類方向回溯給我們找到了變量搜尋的起點(diǎn),但是這個(gè)回溯的順序是如何確定的呢?上面的例子中繼承關(guān)系是 object->A->B->C->D 的順序,如果是比較復(fù)雜的繼承關(guān)系呢?

 

 class A(object):

  pass

  class B(A):

  def method(self):

  print("B's method")

  class C(A):

  def method(self):

  print("C's method")

  class D(B, C):

  def __init__(self):

  super().method()

  class E(C, B):

  def __init__(self):

  super().method()

  d = D()

  e = E()

  B's method

  C's method

  Python 中提供了一個(gè)類方法 mro() 可以指定搜尋的順序,mro 是Method Resolution Order 的縮寫(xiě),它是類方法而不是實(shí)例方法,可以通過(guò)重載 mro() 方法改變繼承中的方法解析順序,但這需要在元類中完成,在這里只看一下其結(jié)果:

 D.mro()

  [__main__.D, __main__.B, __main__.C, __main__.A, object]

  E.mro()

  [__main__.E, __main__.C, __main__.B, __main__.A, object]

  super() 方法就是沿著 mro() 給出的順序向上尋找起點(diǎn)的:

  super(D, d).method()

  super(E, e).method()

  B's method

  C's method

  super(C, e).method()

  super(B, d).method()

  B's method

  C's method

相關(guān)文章

  • Django入門(mén)優(yōu)缺點(diǎn)及環(huán)境搭建流程

    Django入門(mén)優(yōu)缺點(diǎn)及環(huán)境搭建流程

    這篇文章主要為大家介紹了Django入門(mén)優(yōu)缺點(diǎn)及環(huán)境搭建流程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Python Pygame實(shí)戰(zhàn)之實(shí)現(xiàn)經(jīng)營(yíng)類游戲夢(mèng)想小鎮(zhèn)代碼版

    Python Pygame實(shí)戰(zhàn)之實(shí)現(xiàn)經(jīng)營(yíng)類游戲夢(mèng)想小鎮(zhèn)代碼版

    作為一名模擬經(jīng)營(yíng)類游戲的發(fā)燒友,各種農(nóng)場(chǎng)類、醫(yī)院類、鐵路類的游戲玩兒了很多年。今天用代碼給大家打造一款夢(mèng)想小鎮(zhèn)游戲,希望大家喜歡啦
    2022-12-12
  • 詳解Django+uwsgi+Nginx上線最佳實(shí)戰(zhàn)

    詳解Django+uwsgi+Nginx上線最佳實(shí)戰(zhàn)

    這篇文章主要介紹了Django+uwsgi+Nginx上線最佳實(shí)戰(zhàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • 基于Python制作B站視頻下載小工具

    基于Python制作B站視頻下載小工具

    這篇文章主要為大家介紹一個(gè)小工具,可以用于B站視頻的下載,只需要輸入對(duì)應(yīng)視頻的網(wǎng)頁(yè)地址就可以進(jìn)行下載到本地了。感興趣的可以了解一下
    2022-01-01
  • TensorFlow tf.nn.softmax_cross_entropy_with_logits的用法

    TensorFlow tf.nn.softmax_cross_entropy_with_logits的用法

    這篇文章主要介紹了TensorFlow tf.nn.softmax_cross_entropy_with_logits的用法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • 在Django中創(chuàng)建第一個(gè)靜態(tài)視圖

    在Django中創(chuàng)建第一個(gè)靜態(tài)視圖

    這篇文章主要介紹了在Django中創(chuàng)建第一個(gè)靜態(tài)視圖的方法,與其他編程語(yǔ)言的開(kāi)始一樣,以Hello world作為示例,需要的朋友可以參考下
    2015-07-07
  • Python使用sys.path查看當(dāng)前的模塊搜索路徑

    Python使用sys.path查看當(dāng)前的模塊搜索路徑

    sys.path 是 Python 中的一個(gè)列表,它用于存儲(chǔ)模塊搜索路徑,當(dāng)你使用 import 語(yǔ)句導(dǎo)入一個(gè)模塊時(shí),Python 會(huì)按照 sys.path 列表中的路徑順序來(lái)查找這個(gè)模塊,本文給大家介紹了Python使用sys.path查看當(dāng)前的模塊搜索路徑,需要的朋友可以參考下
    2025-02-02
  • Python中的SortedList詳解

    Python中的SortedList詳解

    這篇文章主要介紹了Python中的SortedList集合詳解,Python的SortedSet是一個(gè)強(qiáng)大的數(shù)據(jù)結(jié)構(gòu),它結(jié)合了列表和集合的特性,你可以使用sortedcontainers模塊中的SortedList類來(lái)創(chuàng)建和操作SortedSet,需要的朋友可以參考下
    2023-09-09
  • python編寫(xiě)暴力破解FTP密碼小工具

    python編寫(xiě)暴力破解FTP密碼小工具

    本文給大家分享了一段自己用python編寫(xiě)的暴力破解FTP密碼的小工具的代碼,原理很簡(jiǎn)單,就是利用多線程調(diào)用相應(yīng)的字典進(jìn)行窮舉測(cè)試,小伙伴們可以自由修改。
    2014-11-11
  • python生成每日?qǐng)?bào)表數(shù)據(jù)(Excel)并郵件發(fā)送的實(shí)例

    python生成每日?qǐng)?bào)表數(shù)據(jù)(Excel)并郵件發(fā)送的實(shí)例

    今天小編就為大家分享一篇python生成每日?qǐng)?bào)表數(shù)據(jù)(Excel)并郵件發(fā)送的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-02-02

最新評(píng)論

古蔺县| 阿尔山市| 安岳县| 九江县| 南雄市| 申扎县| 锦州市| 朝阳县| 大宁县| 新巴尔虎左旗| 治县。| 湖南省| 安丘市| 黑龙江省| 永州市| 淳安县| 长治市| 轮台县| 昌宁县| 南漳县| 上杭县| 苏州市| 酒泉市| 沁阳市| 长岭县| 泾阳县| 丰城市| 托克逊县| 柯坪县| 望城县| 法库县| 吉首市| 曲阳县| 张家界市| 出国| 扶风县| 邹城市| 安泽县| 临沂市| 南木林县| 南靖县|