I was looking at the answer to this question: Is it possible to define a class constant inside an Enum?
What interested me most was the Constant class in Ethan Furman's answer.
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. In the answer Ethan sets the gravitational constant as an instance variable of the class Planet like so:
G = Constant(6.67300E-11)
My testing of this class in 2.7 shows that typing just G gives me this:
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.)
The value is available via G.value. However, in Ethan's answer he uses
return self.G * self.mass / (self.radius * self.radius)
This obviously only works if the value is returned vs the __repr__
output. Now if I change class Constant:
to class Constant(int):
then type G I still get the __repr__
output but if I type G * 4
I get 12
not the error I was getting. (TypeError: unsupported operand type(s) for *: 'instance' and 'int'
)
So clearly something like the int object can output a number when called. Is there a magic method I'm missing that would allow me to do this for the Constant class? 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.
The value is also settable via G.value. Can I lock this down so the Constant class behaves likes an actual constant? (I suspect the answer is no.)
Introduction to Python Class ConstantsAn unchangeable value, assiged, is called a constant. Meaning, constants are the containers that hold some information and cannot be changed further.
Class constants can be useful if you need to define some constant data within a class. A class constant is declared inside a class with the const keyword. Class constants are case-sensitive. However, it is recommended to name the constants in all uppercase letters.
Python Constants A constant is a special type of variable whose value cannot be changed. In Python, constants are usually declared and assigned in a module (a new file containing variables, functions, etc which is imported to the main file).
You cannot declare a variable or value as constant in Python. Just don't change it.
Your class Constant should inherit from object, to be a new style Python class.
In that way Constant will be a so called descriptor. In simple terms, descriptor are a Python construct to customize the behavior of getting and setting a class attribute. 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. 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.
Note that __get__ is invoked only when the descriptor instance is accessed by another class attribute.
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.
You can read more on descriptors on this great article.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With