你可以动态地将类变量添加到子类python吗?

时间:2016-09-12 10:44:52

标签: python inheritance

我在python中有大量的自动生成的类,它们实际上代表了部分通信协议的枚举,它们看起来像这样

# definitions.py

class StatusCodes(ParamEnum):
    Success = 1
    Error = 2
    UnexpectedAlpaca = 3

class AlpacaType(ParamEnum):
    Fuzzy = 0
    ReallyMean = 1

# etc etc etc

以这种方式定义事物使自动生成器和人类都可以轻松修改。 ParamEnum类提供所有功能,获取/设置,比较,转换和创建来自传入的网络数据等。

但是,这些类需要一些额外的元数据。我确实想要将它添加到每个类的源定义中,因为它会降低可读性并打破自动生成器

目前我正在这样做

# param_enum.py

class ParamEnum(object):
    def __init__(self):
        self.__class__._metadata = get_class_metadata(self.__class__)
然而,这对我来说有点低效,因为每次我们实例化其中一个枚举(经常发生)时都会发生这种情况,而不仅仅是定义(元数据不会改变,所以它只需要设置一次)< / p>

我尝试将其添加到定义文件的底部,但也遇到了问题。

class StatusCodes(ParamEnum):
    Success = 1
    Error = 2
    UnexpectedAlpaca = 3

for var in locals():  # or globals? 
    add_metadata(var)
    #doesn't work because it is in the same file, modifying dict while iteratng

在定义类时,是否有一种方法在python中覆盖/添加功能,可以继承到子类?理想情况下,我喜欢像

这样的东西
class ParamEnum(object):
    def __when_class_defined__(cls):
        add_metadata(cls)

1 个答案:

答案 0 :(得分:5)

使用类装饰器

def add_metadata(cls):
    cls._metadata = get_class_metadata(cls)
    return cls

@add_metadata
class StatusCodes(ParamEnum):
    Success = 1
    Error = 2
    UnexpectedAlpaca = 3

你想要做的事实上是拥有装饰器的动机:在创建类或函数之后对其进行修改。

如果您不熟悉装饰者,请阅读this(虽然它有点冗长)。

您也可以使用元类,但它们比装饰器引入更多复杂性。如果您想避免使用额外的装饰线@add_metadata,并且您认为它对于指定的子类ParamEnum而言是多余的,您还可以使用_metadata a descriptor进行惰性评估基类ParamEnum

class MetadataDescriptor(object):
    def __get__(self, obj, cls):
        if cls._metadata_value is None:
            cls._metadata_value = get_class_metadata(cls)
        return cls._metadata_value

class ParamEnum(object):
    _metadata_value = None
    _metadata = MetadataDescriptor()