Python:常量类

时间:2014-09-26 20:37:32

标签: python class enums

我正在看这个问题的答案: Is it possible to define a class constant inside an Enum?

最让我感兴趣的是Ethan Furman的答案中的Constant课程。

class Constant:
    def __init__(self, value):
        self.value = value
    def __get__(self, *args):
        return self.value
    def __repr__(self):
        return '%s(%r)' % (self.__class__.__name__, self.value)

问题是关于Python 3.4,但我使用的是2.7。在答案中,Ethan将引力常数设置为Planet类的实例变量,如下所示:

G = Constant(6.67300E-11)

我在2.7中对这个类的测试表明,只输入G就是这样:

Out[49]: Constant(3)

(我将它设置为3以便于测试时使用。这看起来像__repr__输出给我,如果我错了,请纠正我。)

该值可通过G.value获得。但是,在Ethan的回答中,他使用了

return self.G * self.mass / (self.radius * self.radius)

这显然只有在相对于__repr__输出返回值时才有效。现在,如果我将class Constant:更改为class Constant(int):然后输入G,我仍然会获得__repr__输出,但如果我输入G * 4,我会得到12而不是我得到的错误。 (TypeError:不支持的*:'instance'和'int'的操作数类型 )

很明显像int对象这样的东西在调用时可以输出一个数字。有没有一种我想要的魔术方法可以让我为Constant类做这个?由于常量可以是字符串,整数或浮点数,因此我更倾向于使用1个处理它们的类,而不是扩展这些对象的3个单独的类。

该值也可通过G.value设定。我可以将其锁定,以便Constant类的行为类似于实际的常量吗? (我怀疑答案是否定的。)

2 个答案:

答案 0 :(得分:2)

你的类Constant应该从object继承,成为一个新的Python类。

以这种方式,Constant将是一个所谓的描述符。简单来说,描述符是一个Python构造,用于自定义获取和设置类属性的行为。当描述符的实例被设置为另一个类的属性时,它们很有用。

在你的例子中,Constant是描述符,Planet有一个属性,它是Constant的一个实例。当你得到Planet类的属性G(在你的例子中是self.G)时,你真正得到的是描述符的__get__方法返回的值,即值。

请注意,仅当描述符实例被另一个类属性访问时才会调用__get__。

所以,定义这样的类:

class Constant(object):
    def __init__(self, value):
        self.value = value
    def __get__(self, *args):
        return self.value
    def __repr__(self):
        return '%s(%r)' % (self.__class__.__name__, self.value)

然后这个小例子:

c = Constant(3.14)
print c

class Test:
    c = Constant(3.14)

t = Test()
print t.c

将打印:

Constant(3.14)
3.14

看到直接打印Constant实例时,将调用方法__repr__,但是当作为另一个类属性打印时,将使用__get__。

您可以在this great article上阅读有关描述符的更多信息。

答案 1 :(得分:0)

好吧,value是您class Constant的成员;所以你可以尝试making it private

class Constant:
  def __init__(self, value):
    # This actually transforms the variable to _Constant__value, 
    # but also hides it from outer scope
    self.__value = value
  def __get__(self, *args):
    # Altough the member is theorically renamed as _Constant__value,
    # it is completely accesible from inside the class as __value
    reurn self.__value
  def __repr__(self):
    return '%s(%r)' % (self.__class__.__name__, self.__value)

另一种方法可能是this recipe

试一试,让我知道。希望能帮到你!