如何在Python中实现类/对象元数据?

1 投票
3 回答
4461 浏览
提问于 2025-04-17 03:43

我正在开发一个结构化数据分析框架,这个框架是基于节点之间的流数据进行工作的。现在,节点是作为框架提供的根节点类的子类来实现的。对于每个节点类或工厂,我需要一些元数据,比如节点的属性列表、它们的描述和节点的输出。这些元数据可能是给最终用户在前端应用中使用的,也可能是给程序员使用的,比如一些其他的流管理工具。将来还会有更多这样的工具。

(注意,我在写这段代码的时候刚开始学习Python)

目前,元数据是通过一个类变量来提供的。

class AggregateNode(base.Node):
    """Aggregate"""

    __node_info__ = {
        "label" : "Aggregate Node",
        "description" : "Aggregate values grouping by key fields.",
        "output" : "Key fields followed by aggregations for each aggregated field. Last field is "
                   "record count.",
        "attributes" : [
            {
                 "name": "keys",
                 "description": "List of fields according to which records are grouped"
            },
            {
                "name": "record_count_field",
                 "description": "Name of a field where record count will be stored. "
                                "Default is `record_count`"
            }
        ]
    }

更多示例可以在这里找到。

我觉得可以用更简洁的方式来实现。这里有一个限制:因为节点是自定义的子类,所以应该尽量减少与未来可能出现的属性名称的冲突。

我在想的是把现在的node_info拆分开来。它本来是打算私有化给框架使用的,但现在我意识到它的用途更广泛。我在考虑使用节点属性:这样可以有一个公共的属性命名空间,不会占用太多可能的自定义节点属性的名称。

我的问题是:在Python程序中,提供这种元数据的最常见方式是什么?用一个包含字典的单一变量?每个元数据属性用多个变量?(这样会与限制冲突)自定义类/结构?使用某种前缀,比如node_*,然后用多个变量?

3 个回答

0

在Python类中,唯一能够修改类定义本身(也就是元数据)的元素是__new__()这个函数。这个函数在对象真正被创建之前就会被调用,也就是在对象初始化之前。你可以利用这个函数在对象用__init__()进行初始化之前,读取或修改你的类或节点的内部结构。

1

你所描述的很多功能其实和epydoc有很多相似之处:

>>> class AggregateNode(base.Node):
...     r"""
...     Aggregate values grouping by key fields.
... 
...     @ivar keys: List of fields according to which records are grouped
... 
...     @ivar record_count_field: Name of a field where record count will be
...                               stored.
...     """
...     record_count_field = "record_count"
...     
...     def get_output(self):
...         r"""
...         @return: Key fields followed by aggregations for each aggregated field.
...                  Last field is record count.
...         """
... 
>>> import epydoc.docbuilder
>>> api = epydoc.docbuilder.build_doc(AggregateNode)
>>> api.variables['keys'].descr.to_plaintext(None)
u'List of fields according to which records are grouped\n\n'
>>> api.variables['record_count_field'].value.pyval
'record_count'
1

我不太确定在Python对象中存储自定义元数据是否有什么“标准”的方法,但举个例子,Python的dbus实现会在发布的方法和信号前加上一个"_dbus"的前缀。

撰写回答