[英]Using attr module and metaclasses in Python
I am trying to use the attr
package to simply create a metaclass with attributes and methods to use in a further class definition in Python 3. I want to use the attrs
package since I have a lot of simple storage classes that only need a few attributes关于初始化。 一切正常,除了当我试图将元类添加到主 class 时,代码失败
TypeError: __init__() takes from 1 to 2 positional arguments but 4 were given
一个简单的 MWE 将是:
from attr import attrs, attrib
from abc import ABCMeta
@attrs
class MetaClass(ABCMeta):
my_attribute = attrib()
def my_method(self):
pass
class MyClass(object, metaclass=MetaClass):
pass
对于 Python 2/3 兼容性,我通常使用六个 package 和其中的add_metaclass
装饰器,但如果它可以在 ZA7F5F35426B927411FC9231B5638 中工作,我会很高兴。
attrs
库确实为它正在装饰的 class 生成了一个__init__
方法。 但是,元类对__new__
和__init__
方法具有明确定义的签名,只要执行class
语句(连同其主体),它的 arguments 由 Python 运行时本身填充。
I mean - it is the Python runtime that fills in the arguments " class, name, bases, namespace
" in a call for a metaclass __init__
, and you can't easily change that so that class, attr1, attr2
are passed instead, as attrs
创建的__init__
需要。
简而言之,如果不进一步查看attrs
文档以查看是否可以抑制它对__init__
(以及它创建的其他一些魔术方法)的覆盖,则不能将attrs
与元类一起使用。
作为记录,Python 3.7“数据类”允许“关闭”创建__init__
方法,但即便如此,元类还是必须仔细考虑的东西,很难想到一个高级功能仅仅因为语言语法允许,对元类开箱即用的检测类。
总而言之,这可能是一个“x,y”问题——我建议不要尝试将第 3 方 package 与元类一起使用,只是因为您认为它的某些功能在那里可以很好地发挥作用,而是描述那是什么您想在另一个问题中使用自定义元类来实现。
元类__new__
方法中的几行代码可能会为您提供所需的功能,但不会产生未知的副作用。
特别是,如果您只想将my_attribute = attrib()
添加到使用自定义元类创建的所有类中,则不应尝试在元类中创建它。 也许,您只需要一个 Base 超类,根本不需要元类:
from abc import ABC
...
@attrs
class Base(ABC):
my_attribute = attrib()
class MyClass(Base):
pass
同样,我不知道attr
库,也许它不适用于 inheritance (但我怀疑 - 它应该做得很好),然后你可以使用元类来注入属性并将@attrs
装饰器应用到你的类,但不要尝试在你的元类本身上:
from attr import attrs, attrib
from abc import ABCMeta
class MetaClass(ABCMeta):
my_attribute = attrib()
def __new__(metacls, name, bases, namespace, **kw):
cls = super().__new__(metacls, name, bases, namespace, **kw)
# if the 'attrs' decorator modifies the type of "cls",
# the original __init__ won't be called automatically.
# since we are inheriting from other superclass, we'd better
# call it manually here, and suppress its automatic execution
# bellow.
super(MetaClass, cls).__init__(cls, name, bases, namespace, **kw)
cls.my_attribute = attrib()
return attrs(cls)
def __init__(cls, name, bases, namespace, **kw):
pass
class MyClass(object, metaclass=MetaClass):
pass
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.