欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

python的metaclass使用小結

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

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

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

假設我們需要動態(tài)創(chuàng)建一個class,那么一般我們有這樣幾種方法

  • 通過一個函數動態(tài)創(chuàng)建class
  • 通過type動態(tài)創(chuàng)建class

1.函數動態(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動態(tài)創(chuàng)建class

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

  • name: 類名
  • bases: 父類名的tuple,用于繼承,可以為空
  • dict: 字典,包含class attributes的 name 和 value
class ClassParent(object):
    first_name = 'John'
# 創(chuàng)建一個 繼承自 ClassParent 的 ClassChild,并為 ClassChild 添加一個 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

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

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

使用metaclass創(chuàng)建class

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

python2

在 class 的定義中,可以通過 __metaclass__ 來指定當前 class 的 metaclass:

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

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

看一個復雜些的例子

class FooMeta(type):
	def __new__(mcs, name, bases, attrs):
		"""
		定制創(chuàng)建 class 的行為
		作為示例,這里將外部傳入的 attrs 的名稱做一些處理:如果以'_'開頭,則轉為小寫
		: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中,指定元類的語法有一點小小的修改:不再使用 __metaclass__,而是在定義 class 時顯式地指定 metaclass:

class Foo(object, metaclass=CustomMetaclass):
    pass

常見用途

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

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

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

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

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

還有一種方法:

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

以下是一個示例代碼:

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

自動統(tǒng)計某種類型

下面是一個簡單的例子演示了如何使用metaclass來自動注冊子類。

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

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

輸出結果為:

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

可以看到,Subclass1和Subclass2都被自動注冊到了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
    #輸出結果:<__main__.MyCard object at 0x03A6FE90> <__main__.MyCard object at 0x03A6FE90>

自動添加屬性和方法

假設我們有一個基類Base,我們希望所有繼承自Base的子類都能夠自動添加一個名為name的屬性和一個名為hello的方法。我們可以定義一個Meta類,該類繼承自type,并重寫其__init__方法,在該方法中實現(xiàn)自動添加屬性和方法的邏輯。然后,我們將Base類的metaclass設置為Meta類,這樣所有繼承自Base的子類都會使用Meta類來創(chuà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中,當我們定義一個類時,解釋器會根據以下順序來選擇metaclass:

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

結尾

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

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

相關文章

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

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

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

    python數字圖像處理之圖像的批量處理

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

    python下載的庫包存放路徑

    在本篇文章里小編給大家整理的是一篇關于python下載的庫包存放路徑,需要的朋友們可以參考學習下。
    2020-07-07
  • 淺談對yield的初步理解

    淺談對yield的初步理解

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

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

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

    Django模板獲取field的verbose_name實例

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

    python用pandas數據加載、存儲與文件格式的實例

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

    matplotlib之pyplot模塊坐標軸標簽設置使用(xlabel()、ylabel())

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

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

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

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

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

最新評論