python - 从元类设置实例变量

标签 python class oop instance metaclass

给定一个元类,或更简单的 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>,在元类中处理。如果 _fieldsModel 类中的一个 class 变量,这将非常容易,但因为它是一个实例变量,我不知道如何将受限字段也添加到它。


话虽这么说,有什么办法可以实现这个目标吗?或者有更好的方法来处理这个问题吗? (我想到了只使用一个元类并在模型上设置一个 _restricted_fields 类变量,然后在类 __init__() 中使用这个变量将限制字段添加到正常字段,但很快模型类就会出现乱七八糟的代码,在我看来,这些代码应该放在代码的另一部分中)。

最佳答案

为此使用元类不是正确的方法。 元类修改类创建行为而不是实例创建行为。您应该使用 __init____new__ 函数来修改实例创建行为。想要为这些事情使用元类就是使用锤子而不是 Screwdriver 在墙上拧螺丝。 ;-)

我建议您使用 __new__ 来实现您想要的。来自Python docs :

__new__() is intended mainly to allow subclasses of immutable types (like int, str, or tuple) 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/

相关文章:

Python字典keys()方法

C# - 需要基类上的接口(interface),但只需要派生类中的实现

java - 在颜色数组中转换随机颜色

c# - 与 OOP 中的抽象概念相关的问题

java - 当 Activity 名称存储在列表中时访问 Activity

python - 如何从基类引用 Python 派生类的 __init__ 方法?

python - 如何在 Python 中模拟 SendGrid 方法

python - 在音频文件开始处测量静音长度(wav)

C++ - 初始化和修改静态类成员

javascript - 创建绑定(bind)生成的对象的新实例