不幸的是,在Python中,类属性不能引用其类名.以下引发了一个名称错误:
class Foo(object):
bar = Foo
Run Code Online (Sandbox Code Playgroud)
在class属性必须引用其类名的情况下(在我的情况下,它是库的验证方案的一部分),最清楚的方法是什么?
以下是我目前的尝试:
class Foo(object):
bar = None
Foo.bar = Foo
Run Code Online (Sandbox Code Playgroud)
这是有效的,但即使使用注释也可能会引起混淆,因为您希望在声明时初始化类属性,而不是在声明类之后.
有没有人有更好的解决方法?
使用元类来自动设置它。
def my_meta(name, bases, attrs):
cls = type(name, bases, attrs)
cls.bar = cls
return cls
class Foo(object):
__metaclass__ = my_meta
>>> print Foo.bar
<class '__main__.Foo'>
Run Code Online (Sandbox Code Playgroud)
您可以定义一个类装饰器,用正在定义的类替换占位符字符串:
def fixup(cls):
placeholder = '@' + cls.__name__
for k,v in vars(cls).items():
if v == placeholder:
setattr(cls, k, cls)
return cls
@fixup
class Foo(object):
bar = '@Foo'
print('Foo.bar: {!r}'.format(Foo.bar)) # -> Foo.bar: <class '__main__.Foo'>
Run Code Online (Sandbox Code Playgroud)
另一种选择是使用__init_subclass__()
Python 3.6 中引入的特殊方法来创建基类,然后从中派生您的类,而不是通用的object
:
class Base(object):
def __init_subclass__(cls, /, **kwargs):
super().__init_subclass__(**kwargs)
cls.bar = cls
class Foo(Base):
pass
print('Foo.bar: {!r}'.format(Foo.bar)) # -> Foo.bar: <class '__main__.Foo'>
Run Code Online (Sandbox Code Playgroud)