类级变量上的 Python 装饰器作为反射的元数据?

d4n*_*4nt 6 python reflection decorator python-decorators

我有一个 python 类(实际上是 Google App Engine 模型),如下所示:

class MyClass(ParentClass):
    variable_one = PropertyClass(...)
    variable_two = PropertyClass(...)
Run Code Online (Sandbox Code Playgroud)

我打算构建一个系统,它可以描述该类的两个实例之间的差异,这两个实例代表不同时间点的实体的两个版本。最终它会产生一个像这样的字符串

"Variable One changed from 'foo' to 'bar', Variable Two changed from empty to 'baz'"
Run Code Online (Sandbox Code Playgroud)

因此,我需要在某个地方存储“variable_one”应显示为“Variable One”等事实。来自 C# 的背景,我的本能是使用属性,例如:

class MyClass : ParentClass
{
    [DisplayName("Variable One")]
    public PropertyClass variable_one;

    [DisplayName("Variable Two")]
    public PropertyClass variable_two;
}
Run Code Online (Sandbox Code Playgroud)

首先,Python 的等价物似乎是装饰器:

class MyClass(ParentClass):
    @display_name("Variable One")
    variable_one = PropertyClass(...)

    @display_name("Variable Two")
    variable_two = PropertyClass(...)
Run Code Online (Sandbox Code Playgroud)

然而,装饰器实际上是在进行函数柯里化,并且由于类变量定义只是将 PropertyClass 的一个实例分配给variable_one 和variable_two,所以看起来这不是有效的python。无论如何,我不知道该怎么写。

一种选择似乎是扩展 PropertyClass...

class MyClass(ParentClass):
    variable_one = MyPropertyClass("Variable One", ...)
    variable_two = MyPropertyClass("Variable Two", ...)
Run Code Online (Sandbox Code Playgroud)

但是正在使用一些不同的属性类,我想向所有这些属性类添加一种常见的行为,因此这似乎需要付出太多的努力。

我想我可以定义一本字典:

class MyClass(ParentClass):
    variable_one = PropertyClass(...)
    variable_two = PropertyClass(...)
    variable_display_names = {
        "variable_one": "Variable One",
        "variable_two": "Variable Two"
    }
Run Code Online (Sandbox Code Playgroud)

但我希望听到一些更有经验的Python开发者关于实现这一目标的最佳、最Python化的方法。

Mar*_*ers 5

数据存储属性类是描述符(如 python@property装饰器),但作为未实现的自定义类,__setattr__您可以在这些对象上设置任意属性:

 class MyClass(ParentClass):
     variable_one = PropertyClass(...)
     variable_one.display_name = "Variable One"

     variable_two = PropertyClass(...)
     variable_two.display_name = "Variable Two"
Run Code Online (Sandbox Code Playgroud)

可以推广到装饰器:

def display_name(dispname):
    def decorate_with_display_name(prop):
        prop.display_name = dispname
        return prop
    return decorate_with_display_name
Run Code Online (Sandbox Code Playgroud)

只要您通过类(而不是实例)访问属性,您就可以再次检索这些值;print type(instance).variable_two.display_name例如,给定一个您可以做的实例。