Python: persistent class

I looked at the answer to this question: Is it possible to define a class constant inside Enum?

I was most interested in 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 Planet class like this:

 G = Constant(6.67300E-11) 

My testing of this class in 2.7 shows that only G input gives me the following:

 Out[49]: Constant(3) 

(I set it to 3 for ease of use during testing. It looks like __repr__ output to me, please correct me if I'm wrong.)

The value is available through 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 returns to __repr__ . 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 for *: 'instance' and 'int')

So it is clear that something like an int object can output a number when called. Is there a magic method that I skip that will allow me to do this for the Constant class? Since constants can be strings, integers or floats, I would prefer to have 1 class that processes them all against 3 separate classes that extend these objects.

The value is also set via G.value. Can I block this so that the Constant class behaves like a real constant? (I suspect the answer is no.)

+7
python enums class
source share
2 answers

Your Constant class must inherit from the object in order to be the new Python class class.

Thus, the constant will be the so-called descriptor. In simple words, a handle is a Python construct for setting the behavior of getting and setting a class attribute. They are useful when the handle instance is set as an attribute of another class.

In your example, Constant is a handle, and Planet has an attribute that is an instance of Constant. When you get the G attribute of the Planet class (self.G in your example), what you really get is what is returned by the descriptor __get__ method, i.e. the value.

Note that __get__ is called only when a different attribute of the class accesses the handle instance.

So, define the class as follows:

 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 tc 

It will be printed:

 Constant(3.14) 3.14 

See that when a Constant instance is printed directly, the __repr__ method will be called, but when printing, __get__ will be used as another class attribute.

Read more about descriptors in this wonderful article .

+2
source share

Well, value is the memeber of your class Constant ; so you can try to make 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 might be this recipe .

Give them a try and give me now. I hope I helped you!

0
source share

All Articles