您可以动态地将类属性/变量添加到python中的子类吗?
Posted
技术标签:
【中文标题】您可以动态地将类属性/变量添加到python中的子类吗?【英文标题】:Can you dynamically add class attributes/variables to a subclass in python? 【发布时间】:2017-01-19 18:53:38 【问题描述】:我在 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__)
然而这让我觉得效率有点低,因为每次我们实例化这些枚举之一时都会发生这种情况(这种情况经常发生),而不仅仅是在定义时(元数据不会改变,所以只需要设置一次)
我尝试将其添加到定义文件的底部,但在那里也遇到了问题。
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)
【问题讨论】:
在 Python 中,类是其元类的实例。也就是说,您可以通过为您的 ParamEnum 提供一个覆盖__new__
的元类来实现此目的。
【参考方案1】:
使用类装饰器
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
是多余的,你也可以在基类 ParamEnum
中使用惰性计算 _metadata
a descriptor。
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()
【讨论】:
我认为描述符比装饰器好。 @AlbertLee 我也认为描述符更优雅。然而,它们是相当高级的“魔法”,这可能是一个障碍,具体取决于维护代码的人。 使用描述符,工作得非常好,并保持我自动生成的文件干净。谢谢!以上是关于您可以动态地将类属性/变量添加到python中的子类吗?的主要内容,如果未能解决你的问题,请参考以下文章
如何根据另一个组件的存在有条件地将类添加到 Magnolia 组件模板?
如果您从一个视图控制器快速移动到另一个视图控制器,如何动态地将值添加到数组中?