Python:在类中创建抽象静态属性
Posted
技术标签:
【中文标题】Python:在类中创建抽象静态属性【英文标题】:Python: Create Abstract Static Property within Class 【发布时间】:2018-08-07 22:12:33 【问题描述】:我真正想做的是这样的:
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
如果我切换装饰器顺序,这将解决静态方法可调用错误:
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
属性(因此子类可以通过 super 访问)。
如何定义一个 Python 类以具有抽象的静态属性/属性?
【问题讨论】:
要拥有类级别(静态)属性,它需要属于元类。 另外,这个:super(Y, Y).var
肯定不行……
【参考方案1】:
这建立在使用__init_subclass__
的其他答案的方法之上。它在除X
本身之外的每个基类(通过其 MRO)中搜索属性。这解决了孙子没有明确覆盖属性的问题。
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__
不是问题。
【讨论】:
【参考方案2】:如果要求它是一个属性是灵活的,你可以定义一个静态抽象方法:
class X:
@staticmethod
@abstractmethod
def var():
pass
class Y(X):
@staticmethod
def var():
return [1, 2]
>>> Y.var()
[1, 2]
【讨论】:
【参考方案3】:也许您的解决方案的变体可能会起作用 - 而不是使用 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__)
)
也许我忽略了一些重要的东西,但它在简单的用例中有效。
【讨论】:
【参考方案4】:如果您知道解决此问题的更传统方法,请告诉我,该方法也适用于使用 __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
我会将此答案保留为未标记,以便有人提出更好的选择。
【讨论】:
以上是关于Python:在类中创建抽象静态属性的主要内容,如果未能解决你的问题,请参考以下文章