【问题标题】:How to autogenerate properties in a metaclass?如何在元类中自动生成属性?
【发布时间】:2015-11-03 09:45:14
【问题描述】:

如何使用元类在 python 中生成属性? 我有一些数据记录,它们之间有一些关系。 我想将每条记录作为一个类型(类)并自动生成这些属性和关系。

我想将此关系指定为数据结构(例如 dict)并自动生成具有属性的类

Record 1
        Field        description
       ----------------------------
        numOfPin      no# of following pin array
        pin_array     array with numOfpin elements
        read_result   if opt_flag bit 0 is set, invalid. ignore this value
        opt_flag       ...
Record 2
   ....

编辑:澄清.. 缺失/无效字段和可选标志的属性逻辑对于所有记录都是相同的。所以我想在元类中抽象这个。

例如在伪 python 代码中:

record1_spec = { 'numOfpin', ('pin_array','numOfPin'),
                 'opt_flag', ('read_result','opt_flag') }
record2_spec = { 'numOfsite', ('site_array','numOfsite'),
                 'opt_flag', ('test_result','opt_flag') }

class MetaClass:
    getter_generator( ele, opt ):
       if opt : return ele
       else return None

    get class name (eg. record1) then fetch record_spec to create class
    for ele in record_spec:
       if ele is tuple type:   # relation between field
           class.attribute[ele[0]] = getter_generator(ele[0], ele[1])


class record1(metaclass = Metaclass):
    ...

然后record1 类将具有在record1_spec 中定义的所有属性。 逻辑是,如果设置了某些选项字段,则某些属性会返回适当的值。

【问题讨论】:

  • 有点不清楚您要做什么以及是否需要元分类来满足您的需求。例如,您打算如何分配字段值?请注意,元类定义了如何创建类本身,而不是如何定义类的实例。
  • @skyking 我想要元类来创建类(对于每个记录类型。不是记录对象!)每个记录 type 都需要有一些属性,这个属性也可以由元类生成。我有基本的想法。但所有在线 python 元类指南/教程都不是很有帮助。
  • 你能提供一个你想如何使用它的例子吗?
  • edit 提出您的问题并添加说明,说明将由class record1(metaclass = Metaclass): 语句生成的类。我不清楚您希望自动生成哪些属性并将其添加到其中(以及它们正在执行的确切操作)。

标签: python python-3.x metaprogramming metaclass


【解决方案1】:

好的,让我们看看兔子洞有多深......

您似乎需要做两件事。一种是动态创建属性,另一种是添加它们。首先让我们看一下属性的创建,这非常简单——通过将@property 放在函数定义之前创建属性,或者作为装饰器的行为——以函数作为参数调用property。所以我们动态创建一个函数,然后调用property,很简单:

def make_property(params):
    def fn(self):
         return use_self_and_params_to_calculate_result(self, params)
    return property(fn)

例如params 可以是一个字段名,然后您可以通过在内部(即fn)函数中执行return getattr(self, fieldname) 来返回它。

现在是下一部分,创建类。类创建中的 metaclass 参数仅直接用于此目的 - 它不必是实际的元类,它只是被调用并且应该返回被视为类的东西。正常的用例虽然是让 metaclass 参数作为类的类型,但在这种情况下我们实际上并不需要它:

def meta(name, bases, attrs):
    attrs = dict(attrs)

    attrs["x"] = make_property("_x")

    return type(name, bases, attrs)

class record1(metaclass=meta):
    pass

现在我们可以通过globals()meta 中查找record1_specmeta"record1" 作为第一个参数调用),但这有什么好玩的。让我们更深入地挖掘兔子洞,meta 只是用你放在基类所在的任何地方调用 - 它恰好是 type 期望它们是类,但我们不需要这样做,我们只需要做当我们打电话给type时,确定这是真的:

def meta(name, bases, attrs):
    record_spec = bases[0]
    bases = bases[1:]

    attrs = dict(attrs)

    examine_record_spec_and_populate_attrs(attrs, record_spec)
    attrs["spec"] = record_spec

    return type(name, bases, attrs)

class record1(['numOfpin', ('pin_array','numOfPin'), 
              'opt_flag', ('read_result','opt_flag')], metaclass=meta):
    pass

如果需要,您可以找到 record1.spec 的规范。如果您的记录规范是键值对(例如dict),您甚至可以在类定义中使用关键字参数:

 def meta(name, bases, attrs, **spec):
    attrs = dict(attrs)

    examine_record_spec_and_populate_attrs(attrs, spec)
    attrs["spec"] = spec

    return type(name, bases, attrs)

class record1(numOfpin = ('pin_array','numOfPin'), 
              opt_flag = ('read_result','opt_flag'), metaclass=meta):
    pass

【讨论】:

    猜你喜欢
    • 2014-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多