给定一个元类,或更简单的 type()
,最后一个参数代表类字典,它负责类变量。我想知道,有没有办法从元类中设置实例变量?
我使用元类的原因是我需要收集一些在创建类时定义的变量并处理它们。但是,此处理的结果需要附加到类的每个实例,而不是类本身,因为结果将是一个列表,该列表因类的一个实例而异。
我将提供一个示例,以便更容易理解。
我有一个 Model
类,定义如下:
class Model(object):
__metaclass__ = ModelType
has_many = None
def __init__(self, **kwargs):
self._fields = kwargs
has_many
class 变量将由某人认为需要的任何模型在类定义中填充。在 __init__()
中,我只是将模型实例化时提供的关键字分配给 instance 变量 _fields
。
然后我有了 ModelType
元类:
class ModelType(type):
def __new__(cls, name, bases, dct):
if 'has_many' in dct:
dct['_restricted_fields'].append([has-many-model-name])
我需要在这里做的事情非常简单。我检查是否有人在他的自定义模型类上定义了 has_many
class 变量,然后将该变量的内容添加到受限字段 列表中。
现在是重要的部分。实例化模型时,我需要 _fields
由两个用于实例化模型的关键字参数和受限字段<组成/em>,在元类中处理。如果 _fields
是 Model
类中的一个 class 变量,这将非常容易,但因为它是一个实例变量,我不知道如何将受限字段也添加到它。
话虽这么说,有什么办法可以实现这个目标吗?或者有更好的方法来处理这个问题吗? (我想到了只使用一个元类并在模型上设置一个 _restricted_fields
类变量,然后在类 __init__()
中使用这个变量将限制字段添加到正常字段,但很快模型类就会出现乱七八糟的代码,在我看来,这些代码应该放在代码的另一部分中)。
最佳答案
为此使用元类不是正确的方法。 元类修改类创建行为而不是实例创建行为。您应该使用 __init__
或 __new__
函数来修改实例创建行为。想要为这些事情使用元类就是使用锤子而不是 Screwdriver 在墙上拧螺丝。 ;-)
我建议您使用 __new__
来实现您想要的。来自Python docs :
__new__()
is intended mainly to allow subclasses of immutable types (likeint
,str
, ortuple
) to customize instance creation. It is also commonly overridden in custom metaclasses in order to customize class creation.
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
MetaModel
负责创建Model
类。它向它创建的任何 Model
类添加一个 _restricted_fields
类变量(该值是一个包含 has_many
类变量的列表)。
Model
类定义了一个默认的has_many
类变量。它还修改了实例创建行为,它为每个创建的实例添加了一个 instance_var
属性。
SubModel
由您的代码的用户创建。它定义了一个 __init__
函数来修改实例创建。请注意,它不会调用任何父类(super class)函数,这不是必需的。 __init__
将 attr
属性添加到每个 SubClass
实例。
关于python - 从元类设置实例变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21500043/