All,
As the title asks, is it possible to change the __get__
method of a Descriptor at run time. I'm in a situation where I've got a function that is being decorated and undecorated on the the fly at run time. I'd like the result of this function to be available as a attribute, similar to what the @property
does. I researched that and found it's a descriptor, but it seems descriptors' __get__
method is read only.
class Test( object ):
def __init__( self ):
self._x = 10
def get_x( self ):
return self._x
@property
def x( self ):
return self.get_x()
The above code does what I want, roughly, in that
get_x
method to my heart's contentinstance.x
returns the correct valueMy issue is that I'd rather not have to create the get_x
method since it's basically unnecessary. I just haven't been able to decorate the __get__
method of x as it is read-only.
Background
I'm writing a turn based strategy game, and I'm using decorators to implement persistent conditions. I'm able to implement these decorators effectively when I use test cases, but the issue is that to get the computed value then, you must use a function call, not an attribute access. This seems like an bad idea because getting values describing a unit would inconsistently use functions or attributes. I'd like to standardize on attributes if I can.
You can override the default "read-only" characteristic of a property
's __get__
attribute using simple inheritance:
class MyProperty( property ): pass
class Test( object ):
def __init__( self ):
self._x = 10
def get_x( self ):
return self._x
@MyProperty
def x( self ):
return self.get_x()
test = Test()
The problem now is that even if you redefine the __get__
attribute of your Text.x
property, on test.x
request python runtime will call MyProperty.__get__(Test.x, test, Test)
So you could rewrite it only there like:
MyProperty.__get__ = lambda self,instance,owner: "the x attribute"
So good option here is to delegate call to some redefinable attribute like:
MyProperty.__get__ = lambda self,instance,owner: self.get(instance,owner)
From now on get attribute of your property in your full control. Also there is bad option to generate separate type for each property-like object. So in good case you could do something like:
class MyProperty( property ):
def __get__(self,instance,owner) :
if not instance: return self
else: return self.get(instance,owner)
class Test( object ):
def __init__( self ):
self._x = 10
def get_x( self ):
return self._x
@MyProperty
def x( self ): pass
@MyProperty
def y(self): pass
x.get = lambda self,clazz: self.get_x()
y.get = lambda self,clazz: "the y property of " + clazz.__name__ + " object"
>>> test = Test()
>>> test.x
10
>>> test.y
'the y property of Test object'