python-使用元类&对象实例中的类属性

发布于 2025-02-01 12:17:52 字数 1128 浏览 1 评论 0原文

我有许多继承常见的类。我需要父级来跟踪在班级级别定义的一堆依赖关系/关系。类似:

class Meta(type):
    ALLDEPENDENCIES = {}
    def __new__(meta, name, bases, attrs):
        if "DEPENDENCIES" in attrs.keys():
            for key, value in attrs.items():
                if key == "DEPENDENCIES":
                    meta.ALLDEPENDENCIES.update(attrs["DEPENDENCIES"])
        return type.__new__(meta, name, bases, attrs)

class DataTable(DataFrameWrapper, metaclass=Meta):
    pass

class Foo(DataTable):
    DEPENDENCIES = {"a":1}

class Bar(DataTable):
    DEPENDENCIES = {"b":2}

从本质上讲,当我创建新类(Foo,bar,baz ...)时,每个类都有一个字典。我需要合并每个字典中的信息。因此,我正在使用元类,如上所示。每个类都是一个依赖性属性,我将所有这些属性收集到Metaclass中定义的Alldsptions属性中。

如果我这样做,它似乎可以很好地工作:

import Foo, Bar
print(Foo.ALLDEPENDENCIES)
>> {"a":1, "b":2}
print(Bar.ALLDEPENDENCIES)
>> {"a":1, "b":2}

但是,如果OBJ实例工作时,则缺少Alldspiensies属性:

f = Foo()
b = Bar()
print(f.ALLDEPENDENCIES)
print(b.ALLDEPENDENCIES)

属性错误 - 没有alldependencies。

我认为在元素中定义的类属性可以从self.myattibute访问,就像依赖关系一样。我在做什么错?

I have a number of classes that inherit a common one. I need the parent class to keep track of a bunch of dependencies/relationships that are defined at the class level. Something like:

class Meta(type):
    ALLDEPENDENCIES = {}
    def __new__(meta, name, bases, attrs):
        if "DEPENDENCIES" in attrs.keys():
            for key, value in attrs.items():
                if key == "DEPENDENCIES":
                    meta.ALLDEPENDENCIES.update(attrs["DEPENDENCIES"])
        return type.__new__(meta, name, bases, attrs)

class DataTable(DataFrameWrapper, metaclass=Meta):
    pass

class Foo(DataTable):
    DEPENDENCIES = {"a":1}

class Bar(DataTable):
    DEPENDENCIES = {"b":2}

So essentially, as I create new classes (Foo, Bar, Baz...) each of them has a dictionary. I need to merge the info from each dictionary. So I'm using the metaclass, as shown above. Each class as an DEPENDENCIES attribute, and I'm gathering all of those into the ALLDEPENDENCIES attribute defined in the metaclass.

If I do this, it seems to work alright:

import Foo, Bar
print(Foo.ALLDEPENDENCIES)
>> {"a":1, "b":2}
print(Bar.ALLDEPENDENCIES)
>> {"a":1, "b":2}

However, when working if obj instances, the ALLDEPENDENCIES attributes is missing:

f = Foo()
b = Bar()
print(f.ALLDEPENDENCIES)
print(b.ALLDEPENDENCIES)

Attribute error - there is no ALLDEPENDENCIES.

I thought that the class attribute defined in the metaclass would be accessible from self.myattribute in the instances, just like DEPENDENCIES is. What am I doing wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

等数载,海棠开 2025-02-08 12:17:52

Meta描述如何创建类,而不是什么将是什么。

meta!= 带有继承属性的父

因此您必须将适当的属性传递到新类中:

class Meta(type):
    _a = {}
    def __new__(meta, name, bases, attrs):
        if "d" in attrs:
            meta._a.update(attrs["d"])
        attrs["a"] = meta._a
        return type.__new__(meta, name, bases, attrs)

class Data:
    pass

class DataTable(Data, metaclass=Meta):
    pass

class Foo(DataTable):
    d = {"a":1}

class Bar(DataTable):
    d = {"b":2}

f = Foo()
print(Foo.a)
print(f.a)
{'a': 1, 'b': 2}
{'a': 1, 'b': 2}

Meta describes how to create class but not what class that will be.

Meta != Parent with inherited attributes

So you have to pass proper attributes into new class:

class Meta(type):
    _a = {}
    def __new__(meta, name, bases, attrs):
        if "d" in attrs:
            meta._a.update(attrs["d"])
        attrs["a"] = meta._a
        return type.__new__(meta, name, bases, attrs)

class Data:
    pass

class DataTable(Data, metaclass=Meta):
    pass

class Foo(DataTable):
    d = {"a":1}

class Bar(DataTable):
    d = {"b":2}

f = Foo()
print(Foo.a)
print(f.a)
{'a': 1, 'b': 2}
{'a': 1, 'b': 2}
季末如歌 2025-02-08 12:17:52

实例类属性搜索不会进入元类 - 仅进入类。 Metaclass可以在每个新类中设置alldspertancies,其__新__ __中的一行,但是如果您想要清洁器代码,则在某种意义上,词典并不是任何地方,您无处不在,您只需通过课程访问属性即可。

使用您的代码,如:

Foo().__class__.ALLDEPENDANCIES  

将从任何地方使用(就像`type(foo())。

为了在新类中设置属性,以便在新创建的类中可以看到它,一个选项是:(


from types import MappingProxyType

class Meta(type):
    ALLDEPENDANCIES = {}
    ALLDEPSVIEW = MappingProxyType(ALLDEPENDANCIES)
    def __new__(meta, name, bases, attrs):
        if "DEPENDANCIES" in attrs.keys():
            for key, value in attrs.items():
                if key == "DEPENDANCIES":
                    meta.ALLDEPENDANCIES.update(attrs["DEPENDANCIES"])
        new_cls = super().__new__(meta, name, bases, attrs)
        new_cls.ALLDEPENDANCIES = meta.ALLDEPSVIEW
        return new_cls

在调用type .__新的__ new __之前,将新的attr插入attrs中插入attrs中)。

在这里,我做了另外两个附加功能:(1)调用super().__新__,而不是对type .__新的__的调用,这允许您的Metaclass与其他Metaclasse综合,如果您的一个类将与其他元素段交叉(例如,如果您使用abc collections.abc ),则可能需要这一点。 (2)使用Mappingproxytype,该图是“仅读”字典视图,并将通过类或实例停止dict的交流直接更新。

Instance class attribute search does not go into the metaclass - just to the class. The metaclass could set ALLDEPENDANCIES in each new class, with a single line in its __new__, but if you want cleaner code, in the sense the dictionary is not aliased everywhere, you can just access the attribute through the class.

Using your code, as is:

Foo().__class__.ALLDEPENDANCIES  

will work from anywhere (just as `type(Foo()).ALLDEPENDANCIES).

In order to set the attribute in the new classes, so that it will be visible in the newly created classes, an option is:


from types import MappingProxyType

class Meta(type):
    ALLDEPENDANCIES = {}
    ALLDEPSVIEW = MappingProxyType(ALLDEPENDANCIES)
    def __new__(meta, name, bases, attrs):
        if "DEPENDANCIES" in attrs.keys():
            for key, value in attrs.items():
                if key == "DEPENDANCIES":
                    meta.ALLDEPENDANCIES.update(attrs["DEPENDANCIES"])
        new_cls = super().__new__(meta, name, bases, attrs)
        new_cls.ALLDEPENDANCIES = meta.ALLDEPSVIEW
        return new_cls

(Inserting the new attr in attrs before calling type.__new__ will also work)

Here I do two other extras: (1) call super().__new__ instead of hardcoding a call to type.__new__: this allows your metaclass to be composable with other metaclasses, which might be needed if one of your classes will cross with other metaclass (for example, if you are using abstract base classes from abc or collections.abc). And (2) using a MappingProxyType which is a "read only" dictionary view, and will stop acidental direct updates of the dict through classes or instances.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文