使用 metaclasses 隐式干预 python 中每个 class 的定义?
Intervene in definition of every class in python implicitly using metaclasses?
我一直在学习元classes,我想知道是否可以为 python 中定义的每个 class 添加一个新属性,而不仅仅是那些显式继承自自定义元 class.
我可以像这样使用自定义元class显式添加新属性
class NewAttrMeta(type):
def __new__(cls, name, bases, attrs):
attrs['new_attr'] = 'new_thing'
return super().__new__(cls, name, bases, attrs)
class A(metaclass=NewAttrMeta):
...
print(A.new_attr)
$ 'new_thing'
但是是否可以在 每个 class 上强制进行这样的更改,而不仅仅是那些明确继承自您的自定义 metaclass?
我想也许因为所有 class 都是 type
类型,如果我用我的自定义元 class 覆盖 type
本身,那么所有新 classes 然后可能会继承它。由于 metaclasses 是 type
的子classes,那么所有以这种方式定义的 classes 仍然有效...
class NewAttrMeta(type):
def __new__(cls, name, bases, attrs):
attrs['new_attr'] = 'new_thing'
return super().__new__(cls, name, bases, attrs)
type = NewMagicMeta
但这只有在 type
再次显式传入时才有效:
class A(type):
...
print(A.new_attr)
$ 'new_thing'
class B():
...
print(B.new_attr)
$ AttributeError: type object 'A' has no attribute 'new_attr'
我到底为什么要这样做?我想看看我是否可以通过覆盖每个 class 的 __getitem__
方法在本地实现被拒绝的 PEP 472: "Support for indexing with keyword arguments" 的一个版本,该方法定义了 __getitem__
的任何版本。我这样做只是为了好玩,所以我会对任何见解或替代方法感兴趣(黑客越多越好!)。
Python 不允许修改内置声明的类型。那
意味着字典、列表、classes 定义在扩展中,例如
Numpy.ndarrays 来自 Python 代码的 "frozen"。
即使在可能的情况下,更改所有 classes 的 metaclass 也不会更改已经定义的 classes。所以,list
,等等......不会受到影响。你可以安排你的程序,这样它可以 "install" 你的 class 创建钩子,然后再导入任何其他具有 class 定义的模块,但是 - 所以它可能会影响 classes 写在 Python代码。 (在扩展中创建的 类 是在 C 代码中定义的,并且无论如何都不通过元 class-class 创建过程)
type
被引用为对象的元 class,因此即使您在内置函数中更改 type
- 这是可能的,但不会自动用作任何人的 metaclass。默认情况下使用它,因为它是 type(object)
返回的内容
综上所述,可以创建一些东西来搜索 现有的 classes 在 运行 Python 程序中, 并且, 每当 class 在 Python 中定义时, 装饰一个 __getitem__
方法, 如果它存在, 接受关键字参数。
但是然后:
PEP 472 中提出的对索引参数的支持需要更改解析器和语言规范 - 仅接受 __getitem__
中的关键字参数不会使 a[b=1]
工作,或者不是语法错误。人们仍然必须写 a.__getitem__(b=1)
__getitem__
中的索引名称对于一种对象来说是非常具体的。 any class 在没有考虑到这一点的情况下设计是没有意义的。如果 a
是一个列表,那么 a[fish='golden']
是什么意思?如果 a
是一个命令怎么办?
总而言之,如果您想出一些在索引中传递名称是有意义的东西,那么您已经拥有了一个非常酷的 class - 然后您可以使用任何方法检索它,并使用 a.get(fish="gold")
的常规括号表示法,或者甚至,如果您编写 __call__
方法:a(fish="gold")
我一直在学习元classes,我想知道是否可以为 python 中定义的每个 class 添加一个新属性,而不仅仅是那些显式继承自自定义元 class.
我可以像这样使用自定义元class显式添加新属性
class NewAttrMeta(type):
def __new__(cls, name, bases, attrs):
attrs['new_attr'] = 'new_thing'
return super().__new__(cls, name, bases, attrs)
class A(metaclass=NewAttrMeta):
...
print(A.new_attr)
$ 'new_thing'
但是是否可以在 每个 class 上强制进行这样的更改,而不仅仅是那些明确继承自您的自定义 metaclass?
我想也许因为所有 class 都是 type
类型,如果我用我的自定义元 class 覆盖 type
本身,那么所有新 classes 然后可能会继承它。由于 metaclasses 是 type
的子classes,那么所有以这种方式定义的 classes 仍然有效...
class NewAttrMeta(type):
def __new__(cls, name, bases, attrs):
attrs['new_attr'] = 'new_thing'
return super().__new__(cls, name, bases, attrs)
type = NewMagicMeta
但这只有在 type
再次显式传入时才有效:
class A(type):
...
print(A.new_attr)
$ 'new_thing'
class B():
...
print(B.new_attr)
$ AttributeError: type object 'A' has no attribute 'new_attr'
我到底为什么要这样做?我想看看我是否可以通过覆盖每个 class 的 __getitem__
方法在本地实现被拒绝的 PEP 472: "Support for indexing with keyword arguments" 的一个版本,该方法定义了 __getitem__
的任何版本。我这样做只是为了好玩,所以我会对任何见解或替代方法感兴趣(黑客越多越好!)。
Python 不允许修改内置声明的类型。那 意味着字典、列表、classes 定义在扩展中,例如 Numpy.ndarrays 来自 Python 代码的 "frozen"。
即使在可能的情况下,更改所有 classes 的 metaclass 也不会更改已经定义的 classes。所以,
list
,等等......不会受到影响。你可以安排你的程序,这样它可以 "install" 你的 class 创建钩子,然后再导入任何其他具有 class 定义的模块,但是 - 所以它可能会影响 classes 写在 Python代码。 (在扩展中创建的 类 是在 C 代码中定义的,并且无论如何都不通过元 class-class 创建过程)type
被引用为对象的元 class,因此即使您在内置函数中更改type
- 这是可能的,但不会自动用作任何人的 metaclass。默认情况下使用它,因为它是type(object)
返回的内容
综上所述,可以创建一些东西来搜索 现有的 classes 在 运行 Python 程序中, 并且, 每当 class 在 Python 中定义时, 装饰一个 __getitem__
方法, 如果它存在, 接受关键字参数。
但是然后:
PEP 472 中提出的对索引参数的支持需要更改解析器和语言规范 - 仅接受
__getitem__
中的关键字参数不会使a[b=1]
工作,或者不是语法错误。人们仍然必须写a.__getitem__(b=1)
__getitem__
中的索引名称对于一种对象来说是非常具体的。 any class 在没有考虑到这一点的情况下设计是没有意义的。如果a
是一个列表,那么a[fish='golden']
是什么意思?如果a
是一个命令怎么办?
总而言之,如果您想出一些在索引中传递名称是有意义的东西,那么您已经拥有了一个非常酷的 class - 然后您可以使用任何方法检索它,并使用 a.get(fish="gold")
的常规括号表示法,或者甚至,如果您编写 __call__
方法:a(fish="gold")