Python - 在对象实例中使用元class & class 属性
Python - using metaclass & class attributes in objec instances
我有许多 classes 继承了一个共同的。我需要父 class 来跟踪在 class 级别定义的一堆 dependancies/relationships。类似于:
class Meta(type):
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"])
return type.__new__(meta, name, bases, attrs)
class DataTable(DataFrameWrapper, metaclass=Meta):
pass
class Foo(DataTable):
DEPENDANCIES = {"a":1}
class Bar(DataTable):
DEPENDANCIES = {"b":2}
基本上,当我创建新的 classes(Foo、Bar、Baz...)时,它们每个都有一个字典。我需要合并每个词典中的信息。所以我正在使用 metaclass,如上所示。每个 class 作为一个 DEPENDANCIES 属性,我将所有这些收集到 metaclass.
中定义的 ALLDEPENDANCIES 属性中
如果我这样做,它似乎工作正常:
import Foo, Bar
print(Foo.ALLDEPENDANCIES)
>> {"a":1, "b":2}
print(Bar.ALLDEPENDANCIES)
>> {"a":1, "b":2}
但是,在处理 if obj 实例时,缺少 ALLDEPENDANCIES 属性:
f = Foo()
b = Bar()
print(f.ALLDEPENDANCIES)
print(b.ALLDEPENDANCIES)
属性错误 - 没有 ALLDEPENDANCIES。
我认为元class 中定义的class 属性可以从实例中的self.myattribute 访问,就像DEPENDANCIES 一样。我做错了什么?
Meta 描述 how
来创建 class 但不是 what
class 那将是。
Meta
!= Parent
具有继承属性
所以你必须将适当的属性传递给新的 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}
实例 class 属性搜索不进入元 class - 仅进入 class。 metaclass 可以在每个新 class 中设置 ALLDEPENDANCIES
,在其 __new__
中有一行,但如果你想要更清晰的代码,在某种意义上字典没有别名在任何地方,您都可以通过 class.
访问属性
按原样使用您的代码:
Foo().__class__.ALLDEPENDANCIES
将在任何地方工作(就像 `type(Foo()).ALLDEPENDANCIES)。
为了在新的classes中设置该属性,使其在新创建的classes中可见,一个选项是:
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__
之前在 attrs 中插入新的 attr 也可以)
这里我做了另外两个额外的事情:(1) 调用 super().__new__
而不是对 type.__new__
的硬编码调用:这允许你的 metaclass 可以与其他 meta[= 组合31=]es,如果你的一个 classes 将与其他 metaclass 交叉(例如,如果你使用来自 [=17= 的抽象基础 classes ] 或 collections.abc
)。并且 (2) 使用 MappingProxyType,它是一个“只读”字典视图,将停止通过 classes 或实例对字典进行酸性直接更新。
我有许多 classes 继承了一个共同的。我需要父 class 来跟踪在 class 级别定义的一堆 dependancies/relationships。类似于:
class Meta(type):
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"])
return type.__new__(meta, name, bases, attrs)
class DataTable(DataFrameWrapper, metaclass=Meta):
pass
class Foo(DataTable):
DEPENDANCIES = {"a":1}
class Bar(DataTable):
DEPENDANCIES = {"b":2}
基本上,当我创建新的 classes(Foo、Bar、Baz...)时,它们每个都有一个字典。我需要合并每个词典中的信息。所以我正在使用 metaclass,如上所示。每个 class 作为一个 DEPENDANCIES 属性,我将所有这些收集到 metaclass.
中定义的 ALLDEPENDANCIES 属性中如果我这样做,它似乎工作正常:
import Foo, Bar
print(Foo.ALLDEPENDANCIES)
>> {"a":1, "b":2}
print(Bar.ALLDEPENDANCIES)
>> {"a":1, "b":2}
但是,在处理 if obj 实例时,缺少 ALLDEPENDANCIES 属性:
f = Foo()
b = Bar()
print(f.ALLDEPENDANCIES)
print(b.ALLDEPENDANCIES)
属性错误 - 没有 ALLDEPENDANCIES。
我认为元class 中定义的class 属性可以从实例中的self.myattribute 访问,就像DEPENDANCIES 一样。我做错了什么?
Meta 描述 how
来创建 class 但不是 what
class 那将是。
Meta
!= Parent
具有继承属性
所以你必须将适当的属性传递给新的 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}
实例 class 属性搜索不进入元 class - 仅进入 class。 metaclass 可以在每个新 class 中设置 ALLDEPENDANCIES
,在其 __new__
中有一行,但如果你想要更清晰的代码,在某种意义上字典没有别名在任何地方,您都可以通过 class.
按原样使用您的代码:
Foo().__class__.ALLDEPENDANCIES
将在任何地方工作(就像 `type(Foo()).ALLDEPENDANCIES)。
为了在新的classes中设置该属性,使其在新创建的classes中可见,一个选项是:
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__
之前在 attrs 中插入新的 attr 也可以)
这里我做了另外两个额外的事情:(1) 调用 super().__new__
而不是对 type.__new__
的硬编码调用:这允许你的 metaclass 可以与其他 meta[= 组合31=]es,如果你的一个 classes 将与其他 metaclass 交叉(例如,如果你使用来自 [=17= 的抽象基础 classes ] 或 collections.abc
)。并且 (2) 使用 MappingProxyType,它是一个“只读”字典视图,将停止通过 classes 或实例对字典进行酸性直接更新。