我真正想做的是这样的事情:
class X(metaclass=abc.ABCMeta):
@abc.abstractAttribute # this doesn't exist
var = [1,2]
class Y(X):
var = X.var + [3,4]
这将强制X
的任何子类实现静态var
属性。
但是没有办法将静态属性定义为抽象。
尝试使用@ abc.abstractmethod,结合属性,我可以接近:
class X(metaclass=abc.ABCMeta):
@property
@abc.abstractmethod
def var(self):
return [1,2]
class Y(X):
@property
def var(self):
return super().var + [3,4]
y=Y(); y.var
根据需要提供[1,2,3,4]
。
但目标是创建静态属性/属性,而不是实例属性/属性。
创建@staticmethod时:
class X(metaclass=abc.ABCMeta):
@property
@staticmethod
@abc.abstractmethod
def var():
return [1,2]
class Y(X):
@property
@staticmethod
def var():
return X.var + [3,4]
...然后y=Y(); y.var
提供TypeError 'staticmethod' object is not callable
如果我切换装饰器顺序,这将解决staticmethod可调用错误:
class X(metaclass=abc.ABCMeta):
@staticmethod
@property
@abc.abstractmethod
def var():
return [1,2]
class Y(X):
@staticmethod
@property
def var():
return X.var + [3,4]
静态方法可行,但属性不会按预期运行:y=Y(); y.var
返回属性本身<property at 0x2c16aa1b3b8>
。
This answer接近所需,但在这种情况下它不起作用,因为基类X
已经具有var
属性(因此子类可以通过超)。
如何定义python类以具有抽象的静态属性/属性?
答案 0 :(得分:1)
如果灵活地要求它是一个属性,则可以定义一个静态抽象方法:
class X:
@staticmethod
@abstractmethod
def var():
pass
class Y(X):
@staticmethod
def var():
return [1, 2]
>>> Y.var()
[1, 2]
答案 1 :(得分:0)
如果您了解更传统的方法来解决此问题,请告诉我,这也适用于使用__slots__
的类。但对于我的用例,以下内容将起作用:
class X:
var = [1,2]
def __init_subclass__(cls):
attr_name = 'var'
if not attr_name in cls.__dict__:
raise NotImplementedError(
"Attribute '{}' has not been overriden in class '{}'" \
.format(attr_name, cls.__name__)
)
class Y(X):
# var = X.var + [3,4] # this will work
pass # this won't work
y = Y()
编辑:使用这种方法还有另一个缺点,即对于不覆盖的孙子女来说,这将是错误的错误:
class Y(X):
var = X.var + [3,4]
y = Y() # this works
class Z(Y):
pass
z = Z() # this errors
我会将这个答案留给没有人注意的人,以便建议更好的选择。
答案 2 :(得分:0)
也许可以对您的解决方案进行一些修改-不用使用 dict 来简单地测试父级和子类静态变量是否是同一对象。 它适用于孙辈和插槽,但权衡是,如果您将None替换为None,或者将其他对象替换为具有相同对象的对象,则会抛出异常。
class X:
var = [1,2]
def __init_subclass__(cls):
if X.var is cls.var:
raise NotImplementedError(
"Attribute '{}' has not been overriden in class '{}'" \
.format('var', cls.__name__)
)
也许我忽略了一些关键的内容,但是它在简单的用例中起作用。
答案 3 :(得分:0)
这基于使用__init_subclass__
的其他答案的方法。它在每个基类(通过其MRO)中搜索属性,X
本身除外。这解决了孙子代不会显式覆盖属性的问题。
class X(metaclass=abc.ABCMeta):
var = [1,2]
def __init_subclass__(cls):
if not any("var" in base.__dict__ for base in cls.__mro__ if base is not X):
raise NotImplementedError(
f"Attribute 'var' has not been overwritten in class '{cls.__name__}'"
)
它不寻址__slots__
。但是,如果您坚持使用类属性来覆盖抽象属性,则在类中定义__slots__
并不是问题。