【问题标题】:Python: Create Abstract Static Property within ClassPython:在类中创建抽象静态属性
【发布时间】: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 肯定不行……

标签: python properties static attributes abstract-class


【解决方案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
        

        我会将此答案保留为未标记,以便有人提出更好的选择。

        【讨论】:

          猜你喜欢
          • 2012-10-01
          • 1970-01-01
          • 2011-11-15
          • 2020-01-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多