Python:在类

时间:2018-02-28 05:41:13

标签: python properties static attributes abstract-class

我真正想做的是这样的事情:

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类以具有抽象的静态属性/属性?

4 个答案:

答案 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__并不是问题。