简体   繁体   English

Python:常量类

[英]Python: Constant Class

I was looking at the answer to this question: Is it possible to define a class constant inside an Enum? 我正在研究这个问题的答案: 是否可以在Enum中定义一个类常量?

What interested me most was the Constant class in Ethan Furman's answer. 最让我感兴趣的是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)

The question was about Python 3.4 but I'm using 2.7. 问题是关于Python 3.4,但我使用的是2.7。 In the answer Ethan sets the gravitational constant as an instance variable of the class Planet like so: 在答案中,Ethan将引力常数设置为Planet类的实例变量,如下所示:

G = Constant(6.67300E-11)

My testing of this class in 2.7 shows that typing just G gives me this: 我在2.7中对这个类的测试表明只输入G就是这样:

Out[49]: Constant(3)

(I set it to 3 for ease of use while testing. This looks like the __repr__ output to me, please correct me if I"m wrong.) (我将它设置为3以便在测试时使用。这看起来像__repr__输出给我,如果我错了,请纠正我。)

The value is available via G.value. 该值可通过G.value获得。 However, in Ethan's answer he uses 但是,在Ethan的回答中他使用了

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

This obviously only works if the value is returned vs the __repr__ output. 这显然只有在从__repr__输出返回值时才有效。 Now if I change class Constant: to class Constant(int): then type GI still get the __repr__ output but if I type G * 4 I get 12 not the error I was getting. 现在,如果我将class Constant:更改为class Constant(int):那么类型GI仍然得到__repr__输出但是如果我键入G * 4我得到12而不是我得到的错误。 (TypeError: unsupported operand type(s) for *: 'instance' and 'int' ) (TypeError:*:'instance'和'int'不支持的操作数类型)

So clearly something like the int object can output a number when called. 很明显像int对象这样的东西在调用时可以输出一个数字。 Is there a magic method I'm missing that would allow me to do this for the Constant class? 有没有一种我想要的魔术方法可以让我为Constant类做这个? Since constants could be strings, integers, or floats I'd prefer to have 1 class that handles them all vs 3 separate classes that extend those objects. 由于常量可以是字符串,整数或浮点数,因此我更倾向于使用1个处理它们的类,而不是扩展这些对象的3个单独的类。

The value is also settable via G.value. 该值也可通过G.value设置。 Can I lock this down so the Constant class behaves likes an actual constant? 我可以将其锁定,以便Constant类的行为类似于实际的常量吗? (I suspect the answer is no.) (我怀疑答案是否定的。)

Your class Constant should inherit from object, to be a new style Python class. 你的类Constant应该从object继承,成为一个新的Python类。

In that way Constant will be a so called descriptor . 以这种方式,Constant将是一个所谓的描述符 In simple terms, descriptor are a Python construct to customize the behavior of getting and setting a class attribute. 简单来说,描述符是一个Python构造,用于自定义获取和设置类属性的行为。 They are useful when an instance of a descriptor is set as an attribute of another class. 当描述符的实例被设置为另一个类的属性时,它们很有用。

In your example Constant is the descriptor and Planet has an attribute which is an instance of Constant. 在你的例子中,Constant是描述符,Planet有一个属性,它是Constant的一个实例。 When you get the attribute G of the Planet class (self.G in you example), what you really get is what is returned by the __get__ method of the descriptor, that is the value. 当你得到Planet类的属性G(在你的例子中是self.G)时,你真正得到的是描述符的__get__方法返回的值,即值。

Note that __get__ is invoked only when the descriptor instance is accessed by another class attribute. 请注意,仅当描述符实例被另一个类属性访问时才会调用__get__。

So, define the class like this: 所以,定义这样的类:

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)

Then this little example: 然后这个小例子:

c = Constant(3.14)
print c

class Test:
    c = Constant(3.14)

t = Test()
print t.c

Will print: 将打印:

Constant(3.14)
3.14

See that when the Constant instance is printed directly, the method __repr__ will be called, but when printed as another class attribute, __get__ will be used. 看到直接打印Constant实例时,将调用方法__repr__,但是当作为另一个类属性打印时,将使用__get__。

You can read more on descriptors on this great article . 您可以在这篇精彩文章上阅读有关描述符的更多信息。

Well, value is a memeber of your class Constant ; 嗯, value是你的class Constant ; so you can try 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)

Another approach could be following this recipe . 另一种方法可能是遵循这个方法

Give them a try and let me now. 给他们一个尝试,让我现在。 Hope I'd helped you! 希望我能帮到你!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM