属性不是实例属性,而是
descriptor
绑定到访问它的对象的类的属性。下面是一个简单的例子:
class A:
@property
def x(self):
return True
print(A.x) # <property object at 0x0000021AE2944548>
print(A().x) # True
当得到
A.x
,则获取未绑定的属性。当得到
A().x
,属性绑定到实例,并且
A.x.__get__
返回值。
回到你的代码
这意味着
必须是类属性
,不是实例属性。或者,在你的情况下,财产必须是
元类
属性。
class Meta(type):
@property
def abstract(cls):
return getattr(cls, '_abstract', False)
@abstract.setter
def abstract(cls, value):
if value in (True, False):
setattr(cls, '_abstract', value)
else:
raise TypeError(f'invalid abstract assignment {value}')
class Foo(metaclass=Meta):
pass
print(Foo.abstract) # False
Foo.abstract = 'Not at bool' # TypeError: invalid abstract assignment Not at bool
尽管如此,这只部分地解决了您的问题,因为您希望类的每个方法都有
abstract
财产。为此,您需要
他们班
得到那个
property
。
在我们深入讨论之前,让我回顾一下python中的一个关键概念:
我们都是成年人
. 也许你应该相信你的用户不会
摘要
除了一个
bool
让它成为一个非属性属性。特别是,任何用户都可以更改
_abstract
属性本身。
如果这不适合你,你想抽象成
财产
,然后一种方法是为包含
财产
.
class Abstract:
@property
def abstract(cls):
return getattr(cls, '_abstract', False)
@abstract.setter
def abstract(cls, value):
if value in (True, False):
setattr(cls, '_abstract', value)
else:
raise TypeError(f'invalid abstract assignment {value}')
class AbstractCallable(Abstract):
def __init__(self, f):
self.callable = f
def __call__(self, *args, **kwargs):
return self.callable(*args, **kwargs)
class Meta(type, Abstract):
def __new__(mcls, name, bases, dct, **kwargs):
for name, value in dct.items():
if callable(value):
dct[name] = AbstractCallable(value)
return super().__new__(mcls, name, bases, dct)
class Foo(metaclass=Meta):
def bar(self):
pass
print(Foo.abstract) # False
print(Foo.bar.abstract) # False
Foo.bar.abstract = 'baz' # TypeError: invalid abstract assignment baz