簡體   English   中英

通過裝飾器在Python中動態繼承

[英]dynamic inheritance in Python through a decorator

我發現這篇文章中使用了一個函數來繼承一個類:

def get_my_code(base):
    class MyCode(base):
        def initialize(self):
          ...
    return MyCode
my_code = get_my_code(ParentA)

我想做類似的事情,但是要用一個裝飾器,例如:

@decorator(base)
class MyClass(base):
   ...

這可能嗎?

UPDATE

假設您有一個在整個代碼中都使用的Analysis類。 然后,您意識到要使用包裝類Transient ,該包裝類只是分析類頂部的時間循環。 如果在代碼中我替換了分析類,但是Transient(Analysis)一切都中斷了,因為需要一個分析類,因此也需要其所有屬性。 問題是我不能僅僅以這種方式定義class Transient(Analysis) ,因為有很多分析類。 我認為最好的方法是進行某種動態繼承。 現在,我使用聚合將功能重定向到瞬態內部的分析類。

一個類裝飾器實際上獲取已經構建的類-並實例化(作為類對象)。 它可以對字典進行更改,甚至可以將其方法與其他裝飾器包裝在一起。

但是,這意味着該類已經設置了基數-並且這些基數通常無法更改。 這意味着您必須在裝飾器代碼中重新構建類。

但是,如果類的方法使用無參數的super__class__單元格變量,則這些變量已在成員函數中設置(在Python 3中與未綁定方法相同),您不能只是創建一個新類並設置這些方法作為新成員的成員。

因此,也許有一種方法,但這將是不平凡的。 正如我在上面的評論中指出的那樣,我想了解您希望通過此方法實現什么,因為可以將base類放在類聲明本身上,而不是在裝飾器配置上使用它。

我精心設計了一個函數,如上所述,它創建了一個新類,“克隆”原始類,並可以重建使用__class__super所有方法:它返回的新類在功能上與原始類相同,但是與基地交換。 如果按要求在裝飾器中使用(包括裝飾器代碼),它將僅更改類的基數。 它不能處理修飾的方法(除classmethod和staticmethod之外),並且不關心命名細節-例如方法的qualname或repr

from types import FunctionType

def change_bases(cls, bases, metaclass=type):
    class Changeling(*bases, metaclass=metaclass):
        def breeder(self):
            __class__  #noQA

    cell = Changeling.breeder.__closure__
    del Changeling.breeder

    Changeling.__name__ = cls.__name__

    for attr_name, attr_value in cls.__dict__.items():
        if isinstance(attr_value, (FunctionType, classmethod, staticmethod)):
            if isinstance(attr_value, staticmethod):
                func = getattr(cls, attr_name)
            elif isinstance(attr_value, classmethod):
                func = attr_value.__func__
            else:
                func = attr_value
            # TODO: check if func is wrapped in decorators and recreate inner function.
            # Although reaplying arbitrary decorators is not actually possible -
            # it is possible to have a "prepare_for_changeling" innermost decorator
            # which could be made to point to the new function.
            if func.__closure__ and func.__closure__[0].cell_contents is cls:
                franken_func = FunctionType(
                    func.__code__,
                    func.__globals__,
                    func.__name__,
                    func.__defaults__,
                    cell
                )
                if isinstance(attr_value, staticmethod):
                    func = staticmethod(franken_func)
                elif isinstance(attr_value, classmethod):
                    func = classmethod(franken_func)
                else:
                    func = franken_func
                setattr(Changeling, attr_name, func)
                continue
        setattr(Changeling, attr_name, attr_value)

    return Changeling


def decorator(bases):
    if not isinstance(base, tuple):
        bases = (bases,)
    def stage2(cls):
        return change_bases(cls, bases)
    return stage2

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM