Skip to main content
 首页 » 编程设计

python之如何在元类中自动生成属性

2025年05月04日36mate10pro

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

我想将这种关系指定为数据结构(比如字典)并自动生成具有属性的类

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 中定义的所有属性。 逻辑是,如果设置了某些选项字段,则某些属性会返回适当的值。

请您参考如下方法:

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

您似乎需要做两件事。一种是即时创建属性,另一种是添加它们。首先让我们看看属性的创建,这非常简单 - 通过输入 @property 来创建属性。在函数定义之前,或者作为装饰器恰好表现 - 调用 property以函数作为参数。所以我们即时创建一个函数,并调用 property就此而言,很简单:

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

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

现在进入下一部分,创建类。 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 

现在我们可以查找record1_spec在meta通过globals() ( meta 以 "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