从元类设置实例变量

lin*_*ndy 4 python oop metaclass class instance

给定一个元类或更简单的,type()最后一个参数代表类dict,它是一个负责类变量的类.我想知道,有没有办法从元类中设置实例变量?

我使用元类的原因是我需要收集在类创建时定义的一些变量并处理它们.但是,这个处理的结果需要附加到类的每个实例,而不是类本身,因为结果将是一个列表,它将从一个类的实例到另一个实例不同.

我将提供一个示例,以便更容易关注我.


我有一个Model类,定义如下:

class Model(object):
    __metaclass__ = ModelType

    has_many = None

    def __init__(self, **kwargs):
        self._fields = kwargs
Run Code Online (Sandbox Code Playgroud)

has_many 变量在类定义的任何模型有人觉得有必要填写.在__init__(),我只是将模型实例化中提供的关键字分配给实例变量_fields.

然后我有了ModelType元类:

class ModelType(type):
    def __new__(cls, name, bases, dct):
        if 'has_many' in dct:
            dct['_restricted_fields'].append([has-many-model-name])
Run Code Online (Sandbox Code Playgroud)

我在这里需要做的非常简单.我检查是否有人在他的自定义模型类上定义了has_many 变量,然后将变量的内容添加到受限字段列表中.

现在是重要的一部分.当实例化的模型,我需要_fields待由两者关键字用于实例化模型参数和限制字段,如在元类处理.如果_fields中的变量,这将非常容易Model,但由于它是一个实例变量,我不知道如何将限制字段添加到它.


话虽如此,有没有办法实现这一目标?或者有更好的方法来处理这个问题吗?(我想只使用一个元类并_restricted_fields在模型上设置一个类变量,然后在类中使用这个变量__init__()将受限字段添加到普通字段中,但很快模型类就会混杂代码,在我看来,应该在代码的另一部分休息).

sie*_*z0r 6

在这里使用元类不是正确的方法.元类修改类创建行为而不是实例创建行为.您应该使用__init____new__函数来修改实例创建行为.想要使用元类进行此类操作是使用锤子而不是螺丝刀将螺钉拧入墙壁.;-)

我建议你用它__new__来实现你想要的.从Python文档:

__new__()主要是用来允许不可改变的类型(如类的子类int,strtuple)来定制实例创建.它也通常在自定义元类中重写,以自定义类创建.

class MetaModel(type):
    def __new__(cls, name, bases, attrs):
        attrs['_restricted_fields'] = [attrs.get('has_many')]
        return type.__new__(cls, name, bases, attrs)

class Model(object):
    __metaclass__ = MetaModel
    has_many = None
    def __new__(cls, *args, **kwargs):
        instance = object.__new__(cls, *args, **kwargs)
        instance.instance_var = ['spam']
        return instance

class SubModel(Model):
    has_many = True
    def __init__(self):
        # No super call here.
        self.attr = 'eggs'

s = SubModel()
assert s._restricted_fields == [True]  # Added by MetaModel
assert s.instance_var == ['spam']  # Added by Model.__new__
assert s.attr == 'eggs'  # Added by __init__

# instance_var is added per instance.
assert SubModel().instance_var is not SubModel().instance_var
Run Code Online (Sandbox Code Playgroud)

MetaModel负责创建Model类.它将一个_restricted_fields类变量添加到Model由它创建的任何类中(该值是包含has_many类变量的列表).

Model类定义了一个默认has_many类变量.它还修改了实例创建行为,它instance_var为每个创建的实例添加了一个属性.

SubModel由您的代码的用户创建.它定义了一个__init__修改实例创建的函数.请注意,它不会调用任何超类函数,这不是必需的.在__init__增加了attr每个属性SubClass的实例.