在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Python/ 四、自定義元類
二、Enum 的源碼
前言
一、Python 模塊簡介
一、List(列表)
五、匿名函數(shù)
三、什么是元類
二、循環(huán)語句
二、模塊的使用
三、第一個 Python 程序
線程與進程
Python
三、條件語句和循環(huán)語句綜合實例
四、對象的描述器
三、類的屬性
一、迭代
五、迭代器和生成器綜合例子
六、運算符相關的魔術方法
一、枚舉類的使用
前言
一、簡明概述
二、Python 的基本數(shù)據類型
多線程編程
五、作用域
四、包
四、枚舉的比較
四、Python 中的變量
六、類的多態(tài)
一、Python 中類也是對象
一、Python 的 Magic Method
前言
四、生成器
一、面向對象的概念
五、類的繼承
二、類
二、使用 <code>type()</code> 動態(tài)創(chuàng)建類
進程
二、set
三、主模塊和非主模塊
一、字典(Dictionary)
前言
前言
前言
前言
四、集成開發(fā)環(huán)境(IDE): PyCharm
前言
四、函數(shù)的參數(shù)
三、lsit 生成式(列表生成式)
四、自定義元類
四、類的方法
二、函數(shù)傳值問題
二、注釋
一、條件語句
一、Python 語法的簡要說明
三、函數(shù)返回值
三、基本數(shù)據類型轉換
三、屬性的訪問控制
二、Python 的安裝
前言
三、命名規(guī)范
一、Python 自定義函數(shù)的基本步驟
三、自定義類型的枚舉
五、自定義容器(Container)
二、Python 迭代器
前言
二、tuple(元組)
一、Python 簡介
前言
前言
前言
二、構造(<code>__new__</code>)和初始化(<code>__init__</code>)
前言

四、自定義元類

到現(xiàn)在,我們已經知道元類是什么東東了。那么,從始至終我們還不知道元類到底有啥用。只是了解了一下元類。在了解它有啥用的時候,我們先來了解下怎么自定義元類。因為只有了解了怎么自定義才能更好的理解它的作用。

首先我們來了解下 __metaclass__ 屬性

metaclass,直譯為元類,簡單的解釋就是:

當我們定義了類以后,就可以根據這個類創(chuàng)建出實例,所以:先定義類,然后創(chuàng)建實例。

但是如果我們想創(chuàng)建出類呢?那就必須根據metaclass創(chuàng)建出類,所以:先定義metaclass,然后創(chuàng)建類。

連接起來就是:先定義metaclass,就可以創(chuàng)建類,最后創(chuàng)建實例。

所以,metaclass允許你創(chuàng)建類或者修改類。換句話說,你可以把類看成是metaclass創(chuàng)建出來的“實例”。

class MyObject(object):
    __metaclass__ = something…
[…]

如果是這樣寫的話,Python 就會用元類來創(chuàng)建類 MyObject。當你寫下 class MyObject(object),但是類對象 MyObject 還沒有在內存中創(chuàng)建。Python 會在類的定義中尋找 __metaclass__ 屬性,如果找到了,Python 就會用它來創(chuàng)建類 MyObject,如果沒有找到,就會用內建的 type 函數(shù)來創(chuàng)建這個類。如果還不怎么理解,看下下面的流程圖:

__metaclass__的介紹

再舉個實例:

class Foo(Bar):
    pass

它的判斷流程是怎樣的呢?

首先判斷 Foo 中是否有 __metaclass__ 這個屬性?如果有,Python 會在內存中通過 __metaclass__ 創(chuàng)建一個名字為 Foo 的類對象(注意,這里是類對象)。如果 Python 沒有找到__metaclass__ ,它會繼續(xù)在 Bar(父類)中尋找__metaclass__ 屬性,并嘗試做和前面同樣的操作。如果 Python在任何父類中都找不到 __metaclass__ ,它就會在模塊層次中去尋找 __metaclass__ ,并嘗試做同樣的操作。如果還是找不到`metaclass` ,Python 就會用內置的 type 來創(chuàng)建這個類對象。

其實 __metaclass__ 就是定義了 class 的行為。類似于 class 定義了 instance 的行為,metaclass 則定義了 class 的行為??梢哉f,class 是 metaclass 的 instance。

現(xiàn)在,我們基本了解了 __metaclass__ 屬性,但是,也沒講過如何使用這個屬性,或者說這個屬性可以放些什么?

答案就是:可以創(chuàng)建一個類的東西。那么什么可以用來創(chuàng)建一個類呢?type,或者任何使用到 type 或者子類化 type 的東東都可以。

元類的主要目的就是為了當創(chuàng)建類時能夠自動地改變類。通常,你會為API 做這樣的事情,你希望可以創(chuàng)建符合當前上下文的類。假想一個很傻的例子,你決定在你的模塊里所有的類的屬性都應該是大寫形式。有好幾種方法可以辦到,但其中一種就是通過在模塊級別設定__metaclass__ 。采用這種方法,這個模塊中的所有類都會通過這個元類來創(chuàng)建,我們只需要告訴元類把所有的屬性都改成大寫形式就萬事大吉了。

幸運的是,__metaclass__ 實際上可以被任意調用,它并不需要是一個正式的類。所以,我們這里就先以一個簡單的函數(shù)作為例子開始。

# 元類會自動將你通常傳給‘type’的參數(shù)作為自己的參數(shù)傳入
def upper_attr(future_class_name, future_class_parents, future_class_attr):
    '''返回一個類對象,將屬性都轉為大寫形式'''
    #  選擇所有不以'__'開頭的屬性
    attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
# 將它們轉為大寫形式
uppercase_attr = dict((name.upper(), value) for name, value in attrs)

# 通過'type'來做類對象的創(chuàng)建
return type(future_class_name, future_class_parents, uppercase_attr)

__metaclass__ = upper_attr  
#  這會作用到這個模塊中的所有類

class Foo(object):
    # 我們也可以只在這里定義__metaclass__,這樣就只會作用于這個類中
    bar = 'bip'
print hasattr(Foo, 'bar')
# 輸出: False
print hasattr(Foo, 'BAR')
# 輸出:True

f = Foo()
print f.BAR
# 輸出:'bip'

用 class 當做元類的做法:

# 請記住,'type'實際上是一個類,就像'str'和'int'一樣
# 所以,你可以從type繼承
class UpperAttrMetaClass(type):
    # __new__ 是在__init__之前被調用的特殊方法
    # __new__是用來創(chuàng)建對象并返回之的方法
    # 而__init__只是用來將傳入的參數(shù)初始化給對象
    # 你很少用到__new__,除非你希望能夠控制對象的創(chuàng)建
    # 這里,創(chuàng)建的對象是類,我們希望能夠自定義它,所以我們這里改寫__new__
    # 如果你希望的話,你也可以在__init__中做些事情
    # 還有一些高級的用法會涉及到改寫__call__特殊方法,但是我們這里不用
    def __new__(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr):
        attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
        uppercase_attr = dict((name.upper(), value) for name, value in attrs)
        return type(future_class_name, future_class_parents, uppercase_attr)

但是,這種方式其實不是 OOP。我們直接調用了 type,而且我們沒有改寫父類的 __new__ 方法?,F(xiàn)在讓我們這樣去處理:


class UpperAttrMetaclass(type):
    def __new__(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr):
        attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
        uppercase_attr = dict((name.upper(), value) for name, value in attrs)

        # 復用type.__new__方法
        # 這就是基本的OOP編程,沒什么魔法
        return type.__new__(upperattr_metaclass, future_class_name, future_class_parents, uppercase_attr)

你可能已經注意到了有個額外的參數(shù) upperattr_metaclass ,這并沒有什么特別的。類方法的第一個參數(shù)總是表示當前的實例,就像在普通的類方法中的 self 參數(shù)一樣。當然了,為了清晰起見,這里的名字我起的比較長。但是就像 self 一樣,所有的參數(shù)都有它們的傳統(tǒng)名稱。因此,在真實的產品代碼中一個元類應該是像這樣的:

class UpperAttrMetaclass(type):
    def __new__(cls, name, bases, dct):
        attrs = ((name, value) for name, value in dct.items() if not name.startswith('__')
        uppercase_attr  = dict((name.upper(), value) for name, value in attrs)
        return type.__new__(cls, name, bases, uppercase_attr)

如果使用 super 方法的話,我們還可以使它變得更清晰一些,這會緩解繼承(是的,你可以擁有元類,從元類繼承,從 type 繼承)

class UpperAttrMetaclass(type):
    def __new__(cls, name, bases, dct):
        attrs = ((name, value) for name, value in dct.items() if not name.startswith('__'))
        uppercase_attr = dict((name.upper(), value) for name, value in attrs)
        return super(UpperAttrMetaclass, cls).__new__(cls, name, bases, uppercase_attr)

通常我們都會使用元類去做一些晦澀的事情,依賴于自省,控制繼承等等。確實,用元類來搞些“黑暗魔法”是特別有用的,因而會搞出些復雜的東西來。但就元類本身而言,它們其實是很簡單的:

  • 攔截類的創(chuàng)建
  • 修改類
  • 返回修改之后的類