<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ## 問題 你的程序包含一個很大的類繼承體系,你希望強制執行某些編程規約(或者代碼診斷)來幫助程序員保持清醒。 ## 解決方案 如果你想監控類的定義,通常可以通過定義一個元類。一個基本元類通常是繼承自 `type` 并重定義它的 `__new__()` 方法或者是 `__init__()` 方法。比如: class MyMeta(type): def __new__(self, clsname, bases, clsdict): # clsname is name of class being defined # bases is tuple of base classes # clsdict is class dictionary return super().__new__(cls, clsname, bases, clsdict) 另一種是,定義 `__init__()` 方法: class MyMeta(type): def __init__(self, clsname, bases, clsdict): super().__init__(clsname, bases, clsdict) # clsname is name of class being defined # bases is tuple of base classes # clsdict is class dictionary 為了使用這個元類,你通常要將它放到到一個頂級父類定義中,然后其他的類繼承這個頂級父類。例如: class Root(metaclass=MyMeta): pass class A(Root): pass class B(Root): pass 元類的一個關鍵特點是它允許你在定義的時候檢查類的內容。在重新定義 `__init__()` 方法中,你可以很輕松的檢查類字典、父類等等。并且,一旦某個元類被指定給了某個類,那么就會被繼承到所有子類中去。因此,一個框架的構建者就能在大型的繼承體系中通過給一個頂級父類指定一個元類去捕獲所有下面子類的定義。 作為一個具體的應用例子,下面定義了一個元類,它會拒絕任何有混合大小寫名字作為方法的類定義(可能是想氣死Java程序員^_^): class NoMixedCaseMeta(type): def __new__(cls, clsname, bases, clsdict): for name in clsdict: if name.lower() != name: raise TypeError('Bad attribute name: ' + name) return super().__new__(cls, clsname, bases, clsdict) class Root(metaclass=NoMixedCaseMeta): pass class A(Root): def foo_bar(self): # Ok pass class B(Root): def fooBar(self): # TypeError pass 作為更高級和實用的例子,下面有一個元類,它用來檢測重載方法,確保它的調用參數跟父類中原始方法有著相同的參數簽名。 from inspect import signature import logging class MatchSignaturesMeta(type): def __init__(self, clsname, bases, clsdict): super().__init__(clsname, bases, clsdict) sup = super(self, self) for name, value in clsdict.items(): if name.startswith('_') or not callable(value): continue # Get the previous definition (if any) and compare the signatures prev_dfn = getattr(sup,name,None) if prev_dfn: prev_sig = signature(prev_dfn) val_sig = signature(value) if prev_sig != val_sig: logging.warning('Signature mismatch in %s. %s != %s', value.__qualname__, prev_sig, val_sig) # Example class Root(metaclass=MatchSignaturesMeta): pass class A(Root): def foo(self, x, y): pass def spam(self, x, *, z): pass # Class with redefined methods, but slightly different signatures class B(A): def foo(self, a, b): pass def spam(self,x,z): pass 如果你運行這段代碼,就會得到下面這樣的輸出結果: WARNING:root:Signature mismatch in B.spam. (self, x, *, z) != (self, x, z) WARNING:root:Signature mismatch in B.foo. (self, x, y) != (self, a, b) 這種警告信息對于捕獲一些微妙的程序bug是很有用的。例如,如果某個代碼依賴于傳遞給方法的關鍵字參數,那么當子類改變參數名字的時候就會調用出錯。 ## 討論 在大型面向對象的程序中,通常將類的定義放在元類中控制是很有用的。元類可以監控類的定義,警告編程人員某些沒有注意到的可能出現的問題。 有人可能會說,像這樣的錯誤可以通過程序分析工具或IDE去做會更好些。誠然,這些工具是很有用。但是,如果你在構建一個框架或函數庫供其他人使用,那么你沒辦法去控制使用者要使用什么工具。因此,對于這種類型的程序,如果可以在元類中做檢測或許可以帶來更好的用戶體驗。 在元類中選擇重新定義 `__new__()` 方法還是 `__init__()` 方法取決于你想怎樣使用結果類。`__new__()` 方法在類創建之前被調用,通常用于通過某種方式(比如通過改變類字典的內容)修改類的定義。而 `__init__()` 方法是在類被創建之后被調用,當你需要完整構建類對象的時候會很有用。在最后一個例子中,這是必要的,因為它使用了 `super()` 函數來搜索之前的定義。它只能在類的實例被創建之后,并且相應的方法解析順序也已經被設置好了。 最后一個例子還演示了Python的函數簽名對象的使用。實際上,元類會管理中每個一個調用定義,搜索前一個定義(如果有的話),然后通過使用 `inspect.signature()` 來簡單的比較它們的調用簽名。 最后一點,代碼中有一行使用了 `super(self, self)` 并不是排版錯誤。當使用元類的時候,我們要時刻記住一點就是 `self` 實際上是一個類對象。因此,這條語句其實就是用來尋找位于繼承體系中構建 `self` 父類的定義。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看