重载类变量(属性)的pythonic方法是什么?

时间:2018-12-22 21:20:13

标签: python python-3.x

你好!

我需要每个子类都有自己的常量集。我发现了一种使用属性和重载setter方法的“正确”方法,但是:

  1. 我需要在子类中定义构造函数(不需要),并在构造函数中分配值;
  2. 每个类实例在内存中都将具有此常量的副本(无意义的资源消耗);
  3. 当您完全定义setter,getter和property只是将其用作常量时,看起来很奇怪。

我已经做了类似的事情:

class BaseClass:
    def get_a(self):
        raise NotImplementedError("Oooops")

    def get_b(self):
        raise NotImplementedError("Oooops")

class FirstClass(BaseClass):
    def get_a(self):
        return "a"

    def get_b(self):
        return "b"

class SecondClass(BaseClass)
    def get_a(self):
        return "A"

    def get_b(self):
        return "B"

class SomeClass:
    def some_method(self, class_param):
        return "{}-{}".format(class_param.get_a, class_param.get_b)

此方法也不能解决具有属性的方法的问题(最后一个除外),只是更紧凑。还有另一种方法,我觉得不好:

class BaseClass:
    pass

class FirstClass(BaseClass):
    A_CONST = "a"
    B_CONST = "b"

class SecondClass(BaseClass)
    A_CONST = "A"
    B_CONST = "B"

class SomeClass:
    def some_method(self, class_param):
        return "{}-{}".format(class_param.A_CONST, class_param.B_CONST)

实际上,它解决了所有问题并且非常紧凑,但是它违反了继承规则(不是吗?)。

问题: 正确的方法是什么?

P.S。提供的代码是简化的示例,基类包含我在子类中使用的方法,请不要在此告诉我基类没有用。

3 个答案:

答案 0 :(得分:2)

如果您希望基类指示它需要使用某些属性进行子类化,则可以将其设为abstract base class

from abc import ABC, abstractmethod

class Base(ABC):
    @property
    @abstractmethod
    def a(self):
        raise NotImplementedError
    @property
    @abstractmethod
    def b(self):
        raise NotImplementedError

然后将不允许实例化Base或其子类,除非它们重写了抽象方法。你可以做

class First(Base):
    a = 1
    b = 2

使用这些名称分配类属性,或

class Second(Base):
    @Base.a.getter
    def a(self):
        return 3
    @Base.b.getter
    def b(self):
        return 4

第二种方法的好处是,如果您尝试分配给属性,它将引发错误

Second().a = 5  # AttributeError

答案 1 :(得分:0)

您的第二个版本对我来说很好……每种语言对于“类”或“对象”的含义都有自己的约定,而这看起来相当“ Pythonic”

关于第一个版本的一个小评论是Python不在乎“重载”,您不需要包括:

class BaseClass:
    def get_a(self):
        raise NotImplementedError("Oooops")

完全可以,即:

class BaseClass:
    pass

以及您的第一个版本。

这里的另一个可能有用的工具是property装饰器,例如:

class FirstClass(BaseClass):
    @property
    def a(self):
        return "a"

print(FirstClass().a)

将输出“ a

答案 2 :(得分:0)

如果key_name : [A_CONST, B_CONST]类的child保持不变,则super()将解决您的所有问题(1., 2., 3.)。

一种“ pythonic”解决方案将删除setter类中的任何getterchild的重复项,并让BaseClass()处理这些常见任务。 / p>

class BaseClass(object):
    def __init__(self, a, b):
        self._a_const = a
        self._b_const = b
    @property
    def A_CONST(self):
      return self._a_const
    @property
    def B_CONST(self):
      return self._b_const

class FirstClass(BaseClass):
    def __init__(self, _aconst, _bconst):
        # Let Base class object hold my constants but FirstClass Constructor
        # is setting the value. Look SecondClass
        super(FirstClass, self).__init__(_aconst, _bconst)

class SecondClass(BaseClass):
    def __init__(self, _aconst, _bconst):
        # Magic happens here
        super(SecondClass, self).__init__(_aconst, _bconst)

class SomeClass():
    def some_method(self, class_param):
        return "{}-{}".format(class_param.A_CONST, class_param.B_CONST)

firstobj  = FirstClass("a", "b")
secondobj = SecondClass("A", "B")

print(SomeClass().some_method(firstobj))
print(SomeClass().some_method(secondobj))