亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

python的metaclass使用小結(jié)

 更新時(shí)間:2024年01月08日 08:58:50   作者:趙青青  
python中的metaclass可謂熟悉而又陌生,自己開發(fā)時(shí)很少用,閱讀源碼時(shí)卻經(jīng)常遇到,那么到底什么是metaclass呢?何時(shí)使用metaclass呢?這篇文章主要介紹了python的metaclass,需要的朋友可以參考下

python中的metaclass可謂熟悉而又陌生,自己開發(fā)時(shí)很少用,閱讀源碼時(shí)卻經(jīng)常遇到,那么到底什么是metaclass呢?何時(shí)使用metaclass呢?

動(dòng)態(tài)創(chuàng)建class的方法

假設(shè)我們需要?jiǎng)討B(tài)創(chuàng)建一個(gè)class,那么一般我們有這樣幾種方法

  • 通過一個(gè)函數(shù)動(dòng)態(tài)創(chuàng)建class
  • 通過type動(dòng)態(tài)創(chuàng)建class

1.函數(shù)動(dòng)態(tài)創(chuàng)建class

def create_class_by_name(name):
    if name == 'dog': 
        class Dog(object):
            pass
        return Dog
    else:
        class Cat(object):
            pass
        return Cat
dy_class = create_class_by_name('hi')
print dy_class    # output: <class '__main__.Cat'>
print dy_class()  # output: <__main__.Cat object at 0x03601D10>

2.type動(dòng)態(tài)創(chuàng)建class

type 除了可以獲取到一個(gè)對(duì)象的類型,還有另外一個(gè)功能:動(dòng)態(tài)創(chuàng)建 class。
它的函數(shù)簽名是這樣的:_type(name, bases, dict) -> a new type_其中:

  • name: 類名
  • bases: 父類名的tuple,用于繼承,可以為空
  • dict: 字典,包含class attributes的 name 和 value
class ClassParent(object):
    first_name = 'John'
# 創(chuàng)建一個(gè) 繼承自 ClassParent 的 ClassChild,并為 ClassChild 添加一個(gè) age = 15 的 attribute
child_class = type('ClassChild', (ClassParent,), {'age': 15})
# child_class 形如:
class ClassChild(ClassParent):
    age = 15
child_obj = child_class()
print child_obj.first_name, child_obj.age
# output: John 15

事實(shí)上,type 關(guān)鍵字,是 python 用來創(chuàng)建 class 的 metaclass??梢酝ㄟ^ __class__ 來查看一個(gè) class 的 metaclass:

print child_class.__class__
# output <type 'type'>

使用metaclass創(chuàng)建class

metaclass,即是(class of class) class 的 class,用來描述如何創(chuàng)建一個(gè) class 的代碼段。

python2

在 class 的定義中,可以通過 __metaclass__ 來指定當(dāng)前 class 的 metaclass:

因此,只要我們指定了__metaclass__就可以代替type()創(chuàng)建class.我們自己來寫一個(gè)最簡(jiǎn)單的metaclass.

class DemoMeta(type):
	pass
class DemoClass(object):
	__metaclass__ = DemoMeta
print type(DemoClass) #<class '__main__.DemoMeta'>

看一個(gè)復(fù)雜些的例子

class FooMeta(type):
	def __new__(mcs, name, bases, attrs):
		"""
		定制創(chuàng)建 class 的行為
		作為示例,這里將外部傳入的 attrs 的名稱做一些處理:如果以'_'開頭,則轉(zhuǎn)為小寫
		:param name: class 名稱
		:param bases: tuple, 父類的名稱
		:param attrs: class attributes
		"""
		converted = {atr if not atr.startswith('_') else atr.lower(): v 
                     for atr, v in attrs.items()}
		cls = super(FooMeta, mcs).__new__(mcs, name, bases, converted)
		return cls
class Foo(object):
    __metaclass__ = FooMeta

python3

py3中,指定元類的語(yǔ)法有一點(diǎn)小小的修改:不再使用 __metaclass__,而是在定義 class 時(shí)顯式地指定 metaclass:

class Foo(object, metaclass=CustomMetaclass):
    pass

常見用途

metaclass可以控制類的創(chuàng)建過程,包括類的屬性、方法和父類等。metaclass可以用于實(shí)現(xiàn)一些高級(jí)的編程技巧,例如自動(dòng)注冊(cè)子類、自動(dòng)添加屬性和方法等

  • 統(tǒng)計(jì)某種類型
  • 定義一個(gè)單例
  • 自動(dòng)添加屬性和方法

如何統(tǒng)計(jì)某個(gè)類的所有子類#

猜想一下,統(tǒng)計(jì)某個(gè)類的所有子類

__bases__是一個(gè)元組,包含了一個(gè)類的所有直接父類,所以不不能統(tǒng)計(jì)到某種類型

還有一種方法:

使用gc.get_objects()函數(shù)獲取所有已經(jīng)創(chuàng)建的對(duì)象,然后使用issubclass()函數(shù)判斷一個(gè)類是否是另一個(gè)類的子類,從而統(tǒng)計(jì)所有的子類

以下是一個(gè)示例代碼:

import gc
def count_subclasses(cls):
    count = 0
    for obj in gc.get_objects():
        if isinstance(obj, type) and issubclass(obj, cls):
            count += 1
    return count

自動(dòng)統(tǒng)計(jì)某種類型

下面是一個(gè)簡(jiǎn)單的例子演示了如何使用metaclass來自動(dòng)注冊(cè)子類。

假設(shè)我們有一個(gè)基類Base,我們希望所有繼承自Base的子類都能夠自動(dòng)注冊(cè)到一個(gè)全局的字典中。我們可以定義一個(gè)Meta類,該類繼承自type,并重寫其__init__方法,在該方法中實(shí)現(xiàn)自動(dòng)注冊(cè)的邏輯。然后,我們將Base類的metaclass設(shè)置為Meta類,這樣所有繼承自Base的子類都會(huì)使用Meta類來創(chuàng)建實(shí)例,并自動(dòng)注冊(cè)到全局字典中。

class Meta(type):
    registry = {}
    def __init__(cls, name, bases, attrs):
        super(Meta, cls).__init__(name, bases, attrs)
        if name != 'Base':
            Meta.registry[name] = cls
class Base(object):
    __metaclass__ = Meta
class Subclass1(Base):
    pass
class Subclass2(Base):
    pass
print Meta.registry

輸出結(jié)果為:

{'Subclass1': <class '__main__.Subclass1'>, 'Subclass2': <class '__main__.Subclass2'>}

可以看到,Subclass1和Subclass2都被自動(dòng)注冊(cè)到了Meta.registry字典中。這樣,我們就可以方便地獲取所有繼承自Base的子類了。

定義單例

class Singleton(type):
    def __init__(cls, name, bases, dict):
        super(Singleton, cls).__init__(name, bases, dict)
        cls.instance = None
    def __call__(cls, *args):
        if cls.instance is None:
            cls.instance = super(Singleton, cls).__call__(*args)
        return cls.instance
class MyCard(object):
	__metaclass__ = Singleton
def testSingle():
	card1 = MyCard()
	card2= MyCard()
	print card1,card2
    #輸出結(jié)果:<__main__.MyCard object at 0x03A6FE90> <__main__.MyCard object at 0x03A6FE90>

自動(dòng)添加屬性和方法

假設(shè)我們有一個(gè)基類Base,我們希望所有繼承自Base的子類都能夠自動(dòng)添加一個(gè)名為name的屬性和一個(gè)名為hello的方法。我們可以定義一個(gè)Meta類,該類繼承自type,并重寫其__init__方法,在該方法中實(shí)現(xiàn)自動(dòng)添加屬性和方法的邏輯。然后,我們將Base類的metaclass設(shè)置為Meta類,這樣所有繼承自Base的子類都會(huì)使用Meta類來創(chuàng)建實(shí)例,并自動(dòng)添加name屬性和hello方法。

class Meta(type):
    def __init__(cls, name, bases, attrs):
        super(Meta, cls).__init__(name, bases, attrs)
        cls.name = name
        cls.hello = lambda self: 'Hello, %s!' % self.name
class Base(object):
    __metaclass__ = Meta
class Subclass1(Base):
    pass
class Subclass2(Base):
    pass
print Subclass1().hello()
print Subclass2().hello()
#Hello, Subclass1!
#Hello, Subclass2!

Python選取 metaclass 的策略

在Python中,當(dāng)我們定義一個(gè)類時(shí),解釋器會(huì)根據(jù)以下順序來選擇metaclass:

  • 如果該類顯式指定了metaclass,則使用該metaclass。
  • 否則,如果該類的父類中有metaclass,則使用該metaclass。
  • 否則,如果該類的模塊中有metaclass,則使用該metaclass。
  • 否則,如果該類的基類中有metaclass,則使用該metaclass。
  • 否則,使用默認(rèn)的type作為metaclass。

結(jié)尾

如果看完之后你還是看不懂,沒關(guān)系,99%的情況下都不需要用到metaclass

到此這篇關(guān)于python的metaclass的文章就介紹到這了,更多相關(guān)python的metaclass內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • python導(dǎo)入csv文件出現(xiàn)SyntaxError問題分析

    python導(dǎo)入csv文件出現(xiàn)SyntaxError問題分析

    這篇文章主要介紹了python導(dǎo)入csv文件出現(xiàn)SyntaxError問題分析,同時(shí)涉及python導(dǎo)入csv文件的三種方法,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-12-12
  • python數(shù)字圖像處理之圖像的批量處理

    python數(shù)字圖像處理之圖像的批量處理

    這篇文章主要為大家介紹了python數(shù)字圖像處理之圖像的批量處理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • python下載的庫(kù)包存放路徑

    python下載的庫(kù)包存放路徑

    在本篇文章里小編給大家整理的是一篇關(guān)于python下載的庫(kù)包存放路徑,需要的朋友們可以參考學(xué)習(xí)下。
    2020-07-07
  • 淺談對(duì)yield的初步理解

    淺談對(duì)yield的初步理解

    下面小編就為大家?guī)硪黄獪\談對(duì)yield的初步理解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-05-05
  • pandas實(shí)現(xiàn)一行拆分成多行

    pandas實(shí)現(xiàn)一行拆分成多行

    這篇文章主要介紹了pandas實(shí)現(xiàn)一行拆分成多行方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • Django模板獲取field的verbose_name實(shí)例

    Django模板獲取field的verbose_name實(shí)例

    這篇文章主要介紹了Django模板獲取field的verbose_name實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-05-05
  • python用pandas數(shù)據(jù)加載、存儲(chǔ)與文件格式的實(shí)例

    python用pandas數(shù)據(jù)加載、存儲(chǔ)與文件格式的實(shí)例

    今天小編就為大家分享一篇python用pandas數(shù)據(jù)加載、存儲(chǔ)與文件格式的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-12-12
  • matplotlib之pyplot模塊坐標(biāo)軸標(biāo)簽設(shè)置使用(xlabel()、ylabel())

    matplotlib之pyplot模塊坐標(biāo)軸標(biāo)簽設(shè)置使用(xlabel()、ylabel())

    這篇文章主要介紹了matplotlib之pyplot模塊坐標(biāo)軸標(biāo)簽設(shè)置使用(xlabel()、ylabel()),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • Python實(shí)現(xiàn)尋找回文數(shù)字過程解析

    Python實(shí)現(xiàn)尋找回文數(shù)字過程解析

    這篇文章主要介紹了Python實(shí)現(xiàn)尋找回文數(shù)字過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • Django 通過JS實(shí)現(xiàn)ajax過程詳解

    Django 通過JS實(shí)現(xiàn)ajax過程詳解

    這篇文章主要介紹了Django 通過JS實(shí)現(xiàn)ajax過程詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07

最新評(píng)論