<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      翻譯:《實用的Python編程》05_01_Dicts_revisited

      目錄 | 上一節 (4.4 異常) | 下一節 (5.2 封裝)

      5.1 再談字典

      Python 對象系統主要基于字典實現。本節將對此進行討論。

      字典

      字典是命名值(named values)的集合。

      stock = {
          'name' : 'GOOG',
          'shares' : 100,
          'price' : 490.1
      }
      

      雖然字典常用于簡單的數據結構,但是字典也用于解釋器的關鍵部分。字典可能是 Python 中最重要的數據類型

      字典和模塊

      在模塊內,字典存儲所有的全局變量和函數。

      # foo.py
      
      x = 42
      def bar():
          ...
      
      def spam():
          ...
      

      可以通過 foo.__dict__globals() 查看該字典。

      {
          'x' : 42,
          'bar' : <function bar>,
          'spam' : <function spam>
      }
      

      字典和對象

      用戶定義對象的時候也使用到了實例字典和類字典。事實上,整個對象系統主要是基于字典實現的。

      字典存儲實例數據,如 __dict__

      >>> s = Stock('GOOG', 100, 490.1)
      >>> s.__dict__
      {'name' : 'GOOG', 'shares' : 100, 'price': 490.1 }
      

      當給 self 賦值的時候,你將填充該字典(和實例)。

      class Stock:
          def __init__(self, name, shares, price):
              self.name = name
              self.shares = shares
              self.price = price
      

      實例數據 self.__dict__ 看起來像下面這樣:

      {
          'name': 'GOOG',
          'shares': 100,
          'price': 490.1
      }
      

      每一個實例都擁有自己的私有字典。

      s = Stock('GOOG', 100, 490.1)     # {'name' : 'GOOG','shares' : 100, 'price': 490.1 }
      t = Stock('AAPL', 50, 123.45)     # {'name' : 'AAPL','shares' : 50, 'price': 123.45 }
      

      如果你創建了某個類的 100 個實例,那么就會有 100 個存儲數據的字典。

      類成員

      一個單獨的字典也存儲方法:

      class Stock:
          def __init__(self, name, shares, price):
              self.name = name
              self.shares = shares
              self.price = price
      
          def cost(self):
              return self.shares * self.price
      
          def sell(self, nshares):
              self.shares -= nshares
      

      使用 Stock.__dict__ 可以查看該字典:

      {
          'cost': <function>,
          'sell': <function>,
          '__init__': <function>
      }
      

      實例和類

      實例和類是鏈接在一起的。實例通過 __class__ 屬性指向類。

      >>> s = Stock('GOOG', 100, 490.1)
      >>> s.__dict__
      { 'name': 'GOOG', 'shares': 100, 'price': 490.1 }
      >>> s.__class__
      <class '__main__.Stock'>
      >>>
      

      實例字典存儲的數據對每個實例而言是唯一的。但是,類字典存儲的數據被該類的所有實例共享。

      屬性訪問

      使用對象時,可以通過 . 運算符訪問數據和方法。

      x = obj.name          # Getting
      obj.name = value      # Setting
      del obj.name          # Deleting
      

      這些操作直接與字典綁定到一起。

      修改實例

      修改對象的操作會更新底層字典:

      >>> s = Stock('GOOG', 100, 490.1)
      >>> s.__dict__
      { 'name':'GOOG', 'shares': 100, 'price': 490.1 }
      >>> s.shares = 50       # Setting
      >>> s.date = '6/7/2007' # Setting
      >>> s.__dict__
      { 'name': 'GOOG', 'shares': 50, 'price': 490.1, 'date': '6/7/2007' }
      >>> del s.shares        # Deleting
      >>> s.__dict__
      { 'name': 'GOOG', 'price': 490.1, 'date': '6/7/2007' }
      >>>
      

      讀取屬性

      假設你要讀取實例上的屬性:

      x = obj.name
      

      該屬性可能位于兩個地方:

      • 局部實例字典
      • 類字典

      兩種字典都會被檢查到。首先,檢查局部實例字典 __dict__。如果沒有找到,通過 __class__ 查找類字典 __dict__

      >>> s = Stock(...)
      >>> s.name
      'GOOG'
      >>> s.cost()
      49010.0
      >>>
      

      通過這樣的查找模式,類成員被所有實例共享。

      繼承的工作原理

      一個類可能繼承自其它類:

      class A(B, C):
          ...
      

      在每個類中,父類存儲在一個元組中:

      >>> A.__bases__
      (<class '__main__.B'>, <class '__main__.C'>)
      >>>
      

      子類通過 __bases__ 屬性可以鏈接到父類。

      多繼承中的屬性查找

      從邏輯上講,查找屬性的過程如下:首先,檢查局部字典 __dict__。如果沒有找到,檢查類字典 __dict__。如果在類中還是沒有找到,通過 __bases__ 屬性在父類中查找。這里面有一些小細節,我們接下來討論。

      單繼承中的屬性查找

      在繼承層級結構中,通過按順序遍歷繼承樹來找到屬性。

      class A: pass
      class B(A): pass
      class C(A): pass
      class D(B): pass
      class E(D): pass
      

      在單繼承中,因為到達上層父類的路徑只有一條,所以當找到第一個匹配的屬性時即可停止。

      方法解析順序(MRO)

      Python 會預先計算繼承鏈并將其存儲到類的 MRO 屬性中。你可以像這樣查看:

      >>> E.__mro__
      (<class '__main__.E'>, <class '__main__.D'>,
       <class '__main__.B'>, <class '__main__.A'>,
       <type 'object'>)
      >>>
      

      該繼承鏈稱為 方法解析順序(Method Resolution Order)。為了找到屬性,Python 按順序遍歷 MRO,第一個匹配的屬性即是要找的屬性。(譯注:有關 MRO 的更多信息,請查看 https://www.python.org/download/releases/2.3/mro/)。

      多繼承中的方法解析順序

      使用多繼承時,到達上層父類的路徑有很多條,請看示例:

      class A: pass
      class B: pass
      class C(A, B): pass
      class D(B): pass
      class E(C, D): pass
      

      訪問屬性時會發生什么?

      e = E()
      e.attr
      

      會執行屬性查找,那么按什么順序查找呢?這是個問題。

      Python 使用的是 協作多重繼承(cooperative multiple inheritance),協作多繼承遵守的類排序規則如下:

      • 總是在檢查父類之前檢查子類
      • 父類(如果有多個)總是按照列出的順序檢查

      根據該規則, 通過按層級結構對所有的類進行排序,然后計算出方法解析順序。

      >>> E.__mro__
      (
        <class 'E'>,
        <class 'C'>,
        <class 'A'>,
        <class 'D'>,
        <class 'B'>,
        <class 'object'>)
      >>>
      

      底層算法稱為“C3線性化算法(C3 Linearization Algorithm)”,確切的細節不重要,只要記住類層級結構遵守的排序規則與你家房子著火后必須撤離時遵守的規則相同:首先是孩子,其次是父母。

      奇怪的代碼重用(涉及多繼承)

      考慮以下兩個完全不相關的對象:

      class Dog:
          def noise(self):
              return 'Bark'
      
          def chase(self):
              return 'Chasing!'
      
      class LoudDog(Dog):
          def noise(self):
              # Code commonality with LoudBike (below)
              return super().noise().upper()
      

      class Bike:
          def noise(self):
              return 'On Your Left'
      
          def pedal(self):
              return 'Pedaling!'
      
      class LoudBike(Bike):
          def noise(self):
              # Code commonality with LoudDog (above)
              return super().noise().upper()
      

      LoudDog.noise() 方法和LoudBike.noise() 方法中有一些通用的代碼。事實上,這些通用的代碼是完全一樣的。自然,這樣的代碼勢必會吸引軟件工程師。

      "Mixin" 模式

      Mixin 模式(pattern)是包含一部分代碼片段的類。

      class Loud:
          def noise(self):
              return super().noise().upper()
      

      該類不能單獨使用。通過繼承和其它類混合使用。

      class LoudDog(Loud, Dog):
          pass
      
      class LoudBike(Loud, Bike):
          pass
      

      神奇的是,noise() 方法只實現了一次,卻在兩個完全不相關的類中使用。這種技巧是 Python 多繼承的主要用途之一。

      為什么使用 super()

      當要覆蓋一個方法的時候,總是使用 super() 函數。

      class Loud:
          def noise(self):
              return super().noise().upper()
      

      super() 函數代表 MRO 中的下一個類(譯注:LoudDog 的 MRO 是 LoudDog>Loud>Dog>object。因為 Loud 的父類 object 沒有定義 noise() 方法,所以 LoudDog 的實例在 Loud 中找不到 noise() 方法。然后 LoudDog 的實例就會到 MRO 中 Loud 的下一個類 Dog 中尋找)。

      麻煩的是你不知道它是什么,尤其是使用多繼承的時候。

      注意事項

      多繼承是一種強大的機制。使用這種強大的機制時請牢記“權利越大,責任越大”。有時候,框架或者庫使用多繼承來實現一些高級特性,如組件組合。

      練習

      在第 4 節中,定義了一個表示股票持有信息的類 Stock。在本節練習中,我們將使用該類。請重新啟動解釋器并創建一些 Stock 類的實例:

      >>> ================================ RESTART ================================
      >>> from stock import Stock
      >>> goog = Stock('GOOG',100,490.10)
      >>> ibm  = Stock('IBM',50, 91.23)
      >>>
      

      練習 5.1:實例的表示

      在交互式 shell 中,檢查 googibm 兩個實例的底層字典:

      >>> goog.__dict__
      ... look at the output ...
      >>> ibm.__dict__
      ... look at the output ...
      >>>
      

      練習 5.2:修改實例屬性

      嘗試給上述其中一個實例添加新屬性:

      >>> goog.date = '6/11/2007'
      >>> goog.__dict__
      ... look at output ...
      >>> ibm.__dict__
      ... look at output ...
      >>>
      

      在上述輸出中,你會發現 goog 實例具有 date 屬性,但是 ibm 實例沒有。重要的是要注意,Python 對實例屬性確實沒有任何限制。例如,實例屬性不限于 __init__() 方法中設置的屬性。

      嘗試直接添加一個新的值到 __dict__ 對象中:

      >>> goog.__dict__['time'] = '9:45am'
      >>> goog.time
      '9:45am'
      >>>
      

      在這里,你會發現一個事實,實例僅僅是字典頂部的一層。注意:應該強調的是,直接操作字典并不常見——你應該始終使用語法 (.) 編寫代碼。

      練習 5.3:類的作用

      類中的定義被類的所有實例所共享。所有的實例都有一個鏈接,指向它們的關聯類:

      >>> goog.__class__
      ... look at output ...
      >>> ibm.__class__
      ... look at output ...
      >>>
      

      嘗試在實例上調用方法:

      >>> goog.cost()
      49010.0
      >>> ibm.cost()
      4561.5
      >>>
      

      名字 'cost' 既不在 goog.__dict__ 中定義,也不在 ibm.__dict__中定義。相反,而是由類字典提供的。請嘗試以下代碼:

      >>> Stock.__dict__['cost']
      ... look at output ...
      >>>
      

      嘗試直接通過字典調用 cost() 方法:

      >>> Stock.__dict__['cost'](goog)
      49010.0
      >>> Stock.__dict__['cost'](ibm)
      4561.5
      >>>
      

      你是如何調用類中定義的函數,那么 self 就是怎么調用實例的。

      嘗試給 Stock 類添加新屬性::

      >>> Stock.foo = 42
      >>>
      

      該新屬性會出現在所有實例中:

      >>> goog.foo
      42
      >>> ibm.foo
      42
      >>>
      

      但是,foo 并不屬于實例字典:

      >>> goog.__dict__
      ... look at output and notice there is no 'foo' attribute ...
      >>>
      

      你可以訪問 foo 屬性的原因是:當 Python 在實例字典中查找不到某個屬性時,那么它就會到類字典中查找。

      注意:本部分主要闡明什么是類變量。假設你有這樣一個類:

      class Foo(object):
           a = 13                  # Class variable
           def __init__(self,b):
               self.b = b          # Instance variable
      

      在 Foo 類中,因為變量 a 在類體(body of the class)中被賦值,所以 a 是“類變量(class variable)”。變量 a 可以被 Foo 類的所有實例所共享。示例:

      >>> f = Foo(10)
      >>> g = Foo(20)
      >>> f.a          # Inspect the class variable (same for both instances)
      13
      >>> g.a
      13
      >>> f.b          # Inspect the instance variable (differs)
      10
      >>> g.b
      20
      >>> Foo.a = 42   # Change the value of the class variable
      >>> f.a
      42
      >>> g.a
      42
      >>>
      

      練習 5.4:綁定方法

      Python 有一個微妙的特性:調用方法實際上涉及兩個步驟以及一個稱為綁定方法的東西。示例:

      >>> s = goog.sell
      >>> s
      <bound method Stock.sell of Stock('GOOG', 100, 490.1)>
      >>> s(25)
      >>> goog.shares
      75
      >>>
      

      實際上,綁定方法包含調用一個方法的所需的所有內容。例如,它們記錄了實現方法的函數:

      >>> s.__func__
      <function sell at 0x10049af50>
      >>>
      

      這與在 Stock 字典中找到的值是一樣的:

      >>> Stock.__dict__['sell']
      <function sell at 0x10049af50>
      >>>
      

      綁定方法還記錄實例,即 self

      >>> s.__self__
      Stock('GOOG',75,490.1)
      >>>
      

      你可以使用 () 一起調用所有的函數。例如,調用 s(25) 實際是這樣做的:

      >>> s.__func__(s.__self__, 25)    # Same as s(25)
      >>> goog.shares
      50
      >>>
      

      練習 5.5:繼承

      創建一個繼承自 Stock 的類:

      >>> class NewStock(Stock):
              def yow(self):
                  print('Yow!')
      
      >>> n = NewStock('ACME', 50, 123.45)
      >>> n.cost()
      6172.50
      >>> n.yow()
      Yow!
      >>>
      

      通過擴展屬性的搜索過程來實現繼承。__bases__ 屬性是一個包含直接父類的元組:

      >>> NewStock.__bases__
      (<class 'stock.Stock'>,)
      >>>
      

      __mro__ 屬性是一個包含所有父類的元組,父類按查找順序排列。

      >>> NewStock.__mro__
      (<class '__main__.NewStock'>, <class 'stock.Stock'>, <class 'object'>)
      >>>
      

      實例 n 是這樣找到 cost() 方法的:

      >>> for cls in n.__class__.__mro__:
              if 'cost' in cls.__dict__:
                  break
      
      >>> cls
      <class '__main__.Stock'>
      >>> cls.__dict__['cost']
      <function cost at 0x101aed598>
      >>>
      

      目錄 | 上一節 (4.4 異常) | 下一節 (5.2 封裝)

      注:完整翻譯見 https://github.com/codists/practical-python-zh

      posted @ 2021-03-12 08:47  codists  閱讀(255)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 人妻少妇精品视频专区| 久久碰国产一区二区三区| 92久久精品一区二区| 亚洲欧美精品一中文字幕| 久久99精品久久久久久| 久久超碰色中文字幕超清| 欧美疯狂xxxxbbbb喷潮| 中文字幕在线无码一区二区三区| 日本久久一区二区三区高清| 精品国产福利久久久| 4hu44四虎www在线影院麻豆| 蜜臀av日韩精品一区二区 | 午夜A理论片在线播放| 秋霞无码一区二区| 成人精品老熟妇一区二区| 午夜在线观看成人av| 国产中文字幕在线一区| 亚洲最大福利视频网| 中文国产成人精品久久一| 亚洲国产精品一区二区久| 99久久激情国产精品| 国产欧美日韩免费看AⅤ视频| 国产在线午夜不卡精品影院| 黑人大战中国av女叫惨了| 精品亚洲一区二区三区在线观看| 精品日本乱一区二区三区| 高中女无套中出17p| 人妻久久久一区二区三区| 亚洲国产成人精品区综合| 色视频在线观看免费视频| 精品国产成人午夜福利| 在线亚洲午夜片av大片| 西西人体www大胆高清| 国产美女被遭强高潮免费一视频| 国产av丝袜旗袍无码网站| 久久精品国产99久久无毒不卡| 日本一卡二卡不卡视频查询| 中文字幕亚洲综合久久| 午夜福利国产区在线观看| AV教师一区高清| 三级4级全黄60分钟|