成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

Python: 陌生的 metaclass

miya / 1575人閱讀

摘要:但一般情況下,我們使用類作為元類。那么,元類到底有什么用呢要你何用元類的主要目的是為了控制類的創(chuàng)建行為。當(dāng)然,有很多種做法,這里展示用元類的做法。當(dāng)你創(chuàng)建類時(shí),解釋器會(huì)調(diào)用元類來(lái)生成它,定義一個(gè)繼承自的普通類意味著調(diào)用來(lái)創(chuàng)建它。

元類

Python 中的元類(metaclass)是一個(gè)深度魔法,平時(shí)我們可能比較少接觸到元類,本文將通過(guò)一些簡(jiǎn)單的例子來(lái)理解這個(gè)魔法。

類也是對(duì)象

在 Python 中,一切皆對(duì)象。字符串,列表,字典,函數(shù)是對(duì)象,類也是一個(gè)對(duì)象,因此你可以:

把類賦值給一個(gè)變量

把類作為函數(shù)參數(shù)進(jìn)行傳遞

把類作為函數(shù)的返回值

在運(yùn)行時(shí)動(dòng)態(tài)地創(chuàng)建類

看一個(gè)簡(jiǎn)單的例子:

class Foo(object):
    foo = True

class Bar(object):
    bar = True

def echo(cls):
    print cls

def select(name):
    if name == "foo":
        return Foo        # 返回值是一個(gè)類
    if name == "bar":
        return Bar

>>> echo(Foo)             # 把類作為參數(shù)傳遞給函數(shù) echo

>>> cls = select("foo")   # 函數(shù) select 的返回值是一個(gè)類,把它賦給變量 cls
>>> cls
__main__.Foo
熟悉又陌生的 type

在日常使用中,我們經(jīng)常使用 object 來(lái)派生一個(gè)類,事實(shí)上,在這種情況下,Python 解釋器會(huì)調(diào)用 type 來(lái)創(chuàng)建類。

這里,出現(xiàn)了 type,沒(méi)錯(cuò),是你知道的 type,我們經(jīng)常使用它來(lái)判斷一個(gè)對(duì)象的類型,比如:

class Foo(object):
    Foo = True

>>> type(10)

>>> type("hello")

>>> type(Foo())

>>> type(Foo)

事實(shí)上,type 除了可以返回對(duì)象的類型,它還可以被用來(lái)動(dòng)態(tài)地創(chuàng)建類(對(duì)象)。下面,我們看幾個(gè)例子,來(lái)消化一下這句話。

使用 type 來(lái)創(chuàng)建類(對(duì)象)的方式如下:

type(類名, 父類的元組(針對(duì)繼承的情況,可以為空),包含屬性和方法的字典(名稱和值))

最簡(jiǎn)單的情況

假設(shè)有下面的類:

class Foo(object):
    pass

現(xiàn)在,我們不使用 class 關(guān)鍵字來(lái)定義,而使用 type,如下:

Foo = type("Foo", (object, ), {})    # 使用 type 創(chuàng)建了一個(gè)類對(duì)象

上面兩種方式是等價(jià)的。我們看到,type 接收三個(gè)參數(shù):

第 1 個(gè)參數(shù)是字符串 "Foo",表示類名

第 2 個(gè)參數(shù)是元組 (object, ),表示所有的父類

第 3 個(gè)參數(shù)是字典,這里是一個(gè)空字典,表示沒(méi)有定義屬性和方法

在上面,我們使用 type() 創(chuàng)建了一個(gè)名為 Foo 的類,然后把它賦給了變量 Foo,我們當(dāng)然可以把它賦給其他變量,但是,此刻沒(méi)必要給自己找麻煩。

接著,我們看看使用:

>>> print Foo

>>> print Foo()
<__main__.Foo object at 0x10c34f250>
有屬性和方法的情況

假設(shè)有下面的類:

class Foo(object):
    foo = True
    def greet(self):
        print "hello world"
        print self.foo

type 來(lái)創(chuàng)建這個(gè)類,如下:

def greet(self):
    print "hello world"
    print self.foo

Foo = type("Foo", (object, ), {"foo": True, "greet": greet})

上面兩種方式的效果是一樣的,看下使用:

>>> f = Foo()
>>> f.foo
True
>>> f.greet
>
>>> f.greet()
hello world
True
繼承的情況

再來(lái)看看繼承的情況,假設(shè)有如下的父類:

class Base(object):
    pass

我們用 Base 派生一個(gè) Foo 類,如下:

class Foo(Base):
   foo = True

改用 type 來(lái)創(chuàng)建,如下:

Foo = type("Foo", (Base, ), {"foo": True})
什么是元類(metaclass)

元類(metaclass)是用來(lái)創(chuàng)建類(對(duì)象)的可調(diào)用對(duì)象。這里的可調(diào)用對(duì)象可以是函數(shù)或者類等。但一般情況下,我們使用類作為元類。對(duì)于實(shí)例對(duì)象、類和元類,我們可以用下面的圖來(lái)描述:

類是實(shí)例對(duì)象的模板,元類是類的模板

+----------+             +----------+             +----------+
|          |             |          |             |          |
|          | instance of |          | instance of |          |
| instance +------------>+  class   +------------>+ metaclass|
|          |             |          |             |          |
|          |             |          |             |          |
+----------+             +----------+             +----------+

我們?cè)谇懊媸褂昧?type 來(lái)創(chuàng)建類(對(duì)象),事實(shí)上,type 就是一個(gè)元類。

那么,元類到底有什么用呢?要你何用...

元類的主要目的是為了控制類的創(chuàng)建行為。我們還是先來(lái)看看一些例子,以消化這句話。

元類的使用

先從一個(gè)簡(jiǎn)單的例子開(kāi)始,假設(shè)有下面的類:

class Foo(object):
    name = "foo"
    def bar(self):
        print "bar"

現(xiàn)在我們想給這個(gè)類的方法和屬性名稱前面加上 my_ 前綴,即 name 變成 my_name,bar 變成 my_bar,另外,我們還想加一個(gè) echo 方法。當(dāng)然,有很多種做法,這里展示用元類的做法。

1.首先,定義一個(gè)元類,按照默認(rèn)習(xí)慣,類名以 Metaclass 結(jié)尾,代碼如下:

class PrefixMetaclass(type):
    def __new__(cls, name, bases, attrs):
        # 給所有屬性和方法前面加上前綴 my_
        _attrs = (("my_" + name, value) for name, value in attrs.items())  
        
        _attrs = dict((name, value) for name, value in _attrs)  # 轉(zhuǎn)化為字典
        _attrs["echo"] = lambda self, phrase: phrase  # 增加了一個(gè) echo 方法
        
        return type.__new__(cls, name, bases, _attrs)  # 返回創(chuàng)建后的類

上面的代碼有幾個(gè)需要注意的點(diǎn):

PrefixMetaClass 從 type 繼承,這是因?yàn)?PrefixMetaclass 是用來(lái)創(chuàng)建類的

__new__ 是在 __init__ 之前被調(diào)用的特殊方法,它用來(lái)創(chuàng)建對(duì)象并返回創(chuàng)建后的對(duì)象,對(duì)它的參數(shù)解釋如下:

cls:當(dāng)前準(zhǔn)備創(chuàng)建的類

name:類的名字

bases:類的父類集合

attrs:類的屬性和方法,是一個(gè)字典

2.接著,我們需要指示 Foo 使用 PrefixMetaclass 來(lái)定制類。

在 Python2 中,我們只需在 Foo 中加一個(gè) __metaclass__ 的屬性,如下:

class Foo(object):
    __metaclass__ = PrefixMetaclass
    name = "foo"
    def bar(self):
        print "bar"

在 Python3 中,這樣做:

class Foo(metaclass=PrefixMetaclass):
    name = "foo"
    def bar(self):
        print "bar"

現(xiàn)在,讓我們看看使用:

>>> f = Foo()
>>> f.name    # name 屬性已經(jīng)被改變
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
 in ()
----> 1 f.name

AttributeError: "Foo" object has no attribute "name"
>>>
>>> f.my_name
"foo"
>>> f.my_bar()
bar
>>> f.echo("hello")
"hello"

可以看到,F(xiàn)oo 原來(lái)的屬性 name 已經(jīng)變成了 my_name,而方法 bar 也變成了 my_bar,這就是元類的魔法。

再來(lái)看一個(gè)繼承的例子,下面是完整的代碼:

class PrefixMetaclass(type):
    def __new__(cls, name, bases, attrs):
        # 給所有屬性和方法前面加上前綴 my_
        _attrs = (("my_" + name, value) for name, value in attrs.items())  
        
        _attrs = dict((name, value) for name, value in _attrs)  # 轉(zhuǎn)化為字典
        _attrs["echo"] = lambda self, phrase: phrase  # 增加了一個(gè) echo 方法
        
        return type.__new__(cls, name, bases, _attrs)

class Foo(object):
    __metaclass__ = PrefixMetaclass   # 注意跟 Python3 的寫法有所區(qū)別
    name = "foo"
    def bar(self):
        print "bar"

class Bar(Foo):
    prop = "bar"

其中,PrefixMetaclass 和 Foo 跟前面的定義是一樣的,只是新增了 Bar,它繼承自 Foo。先讓我們看看使用:

>>> b = Bar()
>>> b.prop     # 發(fā)現(xiàn)沒(méi)這個(gè)屬性
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
 in ()
----> 1 b.prop

AttributeError: "Bar" object has no attribute "prop"
>>> b.my_prop
"bar"
>>> b.my_name
"foo"
>>> b.my_bar()
bar
>>> b.echo("hello")
"hello"

我們發(fā)現(xiàn),Bar 沒(méi)有 prop 這個(gè)屬性,但是有 my_prop 這個(gè)屬性,這是為什么呢?

原來(lái),當(dāng)我們定義 class Bar(Foo) 時(shí),Python 會(huì)首先在當(dāng)前類,即 Bar 中尋找 __metaclass__,如果沒(méi)有找到,就會(huì)在父類 Foo 中尋找 __metaclass__,如果找不到,就繼續(xù)在 Foo 的父類尋找,如此繼續(xù)下去,如果在任何父類都找不到 __metaclass__,就會(huì)到模塊層次中尋找,如果還是找不到,就會(huì)用 type 來(lái)創(chuàng)建這個(gè)類。

這里,我們?cè)?Foo 找到了 __metaclass__,Python 會(huì)使用 PrefixMetaclass 來(lái)創(chuàng)建 Bar,也就是說(shuō),元類會(huì)隱式地繼承到子類,雖然沒(méi)有顯示地在子類使用 __metaclass__,這也解釋了為什么 Bar 的 prop 屬性被動(dòng)態(tài)修改成了 my_prop。

寫到這里,不知道你理解元類了沒(méi)?希望理解了,如果沒(méi)理解,就多看幾遍吧~

小結(jié)

在 Python 中,類也是一個(gè)對(duì)象。

類創(chuàng)建實(shí)例,元類創(chuàng)建類。

當(dāng)你創(chuàng)建類時(shí),解釋器會(huì)調(diào)用元類來(lái)生成它,定義一個(gè)繼承自 object 的普通類意味著調(diào)用 type 來(lái)創(chuàng)建它。

本文由 funhacks 發(fā)表于個(gè)人博客,采用 Creative Commons BY-NC-ND 4.0(自由轉(zhuǎn)載-保持署名-非商用-禁止演繹)協(xié)議發(fā)布。
非商業(yè)轉(zhuǎn)載請(qǐng)注明作者及出處。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者本人。
本文標(biāo)題為: Python: 陌生的 metaclass
本文鏈接為: https://funhacks.net/2016/11/...

參考資料

oop - What is a metaclass in Python? - Stack Overflow

深刻理解Python中的元類(metaclass) - 伯樂(lè)在線

使用元類 - 廖雪峰的官方網(wǎng)站

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/44251.html

相關(guān)文章

  • [譯]理解pythonmetaclass

    摘要:但我并不是一個(gè)翻譯者并不會(huì)嚴(yán)格遵守每行每句的翻譯有時(shí)候我會(huì)將表述換個(gè)順序省略一些我認(rèn)為無(wú)關(guān)緊要的話,以便讀者更好理解。類也是對(duì)象在理解之前,我們先要掌握中的類是什么。這個(gè)對(duì)象類自身?yè)碛挟a(chǎn)生對(duì)象實(shí)例的能力。不過(guò)這樣做是為了保持向后兼容性。 前言 這篇博客是我在stackoverflow上看了一個(gè)提問(wèn)回復(fù)后寫的,例子基本用的都是e-satis本人的例子,語(yǔ)言組織也基本按照翻譯來(lái)。 但我并不...

    liuchengxu 評(píng)論0 收藏0
  • How does it work - with_metaclass

    摘要:先簡(jiǎn)單介紹下中的元類。元類就是創(chuàng)建類的類,對(duì)于元類來(lái)說(shuō),類是它的實(shí)例,將返回。中的所有類,都是的實(shí)例,換句話說(shuō),是元類的基類。 我在看源代碼的時(shí)候,經(jīng)常蹦出這一句:How does it work!竟然有這種操作?本系列文章,試圖剖析代碼中發(fā)生的魔法。順便作為自己的閱讀筆記,以作提高。 先簡(jiǎn)單介紹下Python中的元類(metaclass)。元類就是創(chuàng)建類的類,對(duì)于元類來(lái)說(shuō),類是它的實(shí)...

    testbird 評(píng)論0 收藏0
  • Python -- 元類metaclass詳解

    摘要:原鏈接中的元類是什么類也是對(duì)象在理解元類之前,需要掌握中類概念。事實(shí)上,是中用于創(chuàng)建所有類的元類。類本身是元類的對(duì)象在中,除了,一切皆對(duì)象,一切都是類或者元類的對(duì)象。事實(shí)上是自己的元類, 學(xué)習(xí)契機(jī) 項(xiàng)目中使用Elasticsearch(ES)存儲(chǔ)海量業(yè)務(wù)數(shù)據(jù),基于ES向外提供的API進(jìn)一層封裝,按需處理原始數(shù)據(jù)提供更精確、更多樣化的結(jié)果。在研究這一層的代碼時(shí)接觸到@six.add_me...

    tracy 評(píng)論0 收藏0
  • python 類和元類(metaclass)理解和簡(jiǎn)單運(yùn)用

    摘要:什么是元類剛才說(shuō)了,元類就是創(chuàng)建類的類。類上面的屬性,相信愿意了解元類細(xì)節(jié)的盆友,都肯定見(jiàn)過(guò)這個(gè)東西,而且為之好奇。使用了這個(gè)魔法方法就意味著就會(huì)用指定的元類來(lái)創(chuàng)建類了。深刻理解中的元類 (一) python中的類 今天看到一篇好文,然后結(jié)合自己的情況總結(jié)一波。這里討論的python類,都基于python2.7x以及繼承于object的新式類進(jìn)行討論。 首先在python中,所有東西都...

    zhangqh 評(píng)論0 收藏0
  • Python: metaclass小記

    摘要:最前面那個(gè),解釋器實(shí)際的流程是解析這段代碼,得知它需要?jiǎng)?chuàng)建一個(gè)類對(duì)象,這個(gè)類的名字叫做它的父類列表用表示是,它的屬性用一個(gè)來(lái)表示就是。解決方法很簡(jiǎn)單關(guān)鍵就是前面被特別標(biāo)記了的應(yīng)當(dāng)返回這個(gè)的父類的方法返回的對(duì)象。 (原發(fā)于我的blog:Python: metaclass小記 ) 友情提示:本文不一定適合閱讀,如果執(zhí)意要讀,請(qǐng)備好暈車藥。 題記 Metaclasses are deepe...

    mushang 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

miya

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<