overriding a property

L

Lucasm

Hi,

A question. Is it possible to dynamically override a property?

class A(object):
@property
def return_five(self):
return 5

I would like to override the property for an instance of A to say the
string 'bla'.
 
J

John Posner

Hi,

A question. Is it possible to dynamically override a property?

class A(object):
@property
def return_five(self):
return 5

I would like to override the property for an instance of A to say the
string 'bla'.

Is this the sort of thing you're looking for ...

#-------------------------------------
import inspect

class A(object):
@property
def return_five(self):
try:
# get name of this function ...
frm = inspect.getframeinfo(inspect.currentframe())
# ... and use it as dict key
return self.__dict__[frm.function]

except KeyError:
# attr not set in instance
return 5

a = A()
print "one:", a.return_five

b = A()
b.__dict__['return_five'] = 'bla'
print "two:", b.return_five

c = A()
print "three:", c.return_five
#-------------------------------------

The output is:

one: 5
two: bla
three: 5

If you don't want to fool around with the inspect module, you can
hard-code the function name as the instance's dict key:

return self.__dict__['return_five']

HTH,
John
 
S

Steven D'Aprano

Hi,

A question. Is it possible to dynamically override a property?

class A(object):
@property
def return_five(self):
return 5

I would like to override the property for an instance of A to say the
string 'bla'.
.... _five = 5 # class attribute shared by all instances
.... @property
.... def return_five(self):
.... return self._five
....5
 
L

Lucasm

...     _five = 5  # class attribute shared by all instances
...     @property
...     def return_five(self):
...         return self._five
...


5

Thanks for the answers. I would like to override the property though
without making special modifications in the main class beforehand. Is
this possible?
 
P

Peter Otten

Lucasm said:
Thanks for the answers. I would like to override the property though
without making special modifications in the main class beforehand. Is
this possible?

You can dynamically change the instance's class:
.... @property
.... def five(self): return 5
........ @property
.... def five(self): return "FIVE"
....'FIVE'

But still -- what you are trying looks like a bad idea. What's your usecase?

Peter
 
L

Lucasm

You can dynamically change the instance's class:


...     @property
...     def five(self): return 5
...>>> a = A()

...     @property
...     def five(self): return "FIVE"
...>>> b.__class__ = B

'FIVE'

But still -- what you are trying looks like a bad idea. What's your usecase?

Peter

Thanks for your answer. That's exactly the thing I'm doing right now
and it works :) My use case is testing. I want to test a class and
reduce the complexity of the output generated by certain properties.
It would be nice to know alternatives to this approach.
 
J

John Posner

On 10/20/2010 9:59 AM, Lucasm wrote:

Thanks for the answers. I would like to override the property though
without making special modifications in the main class beforehand. Is
this possible?

Take a look at http://docs.python.org/reference/datamodel.html#descriptors

The last paragraph of Section 3.4.2.3. Invoking Descriptors says:

The property() function is implemented as a data descriptor.
Accordingly, instances cannot override the behavior of a property.

-John
 
H

Hrvoje Niksic

Lucasm said:
Thanks for the answers. I would like to override the property though
without making special modifications in the main class beforehand. Is
this possible?

That will not be easy. When you access obj.return_five, python looks up
'return_five' in type(obj) to see what the return_five property even
means. (See http://users.rcn.com/python/download/Descriptor.htm for
details of how this works.)

Since you can't change the source of A, you are left with two options:
you can monkey-patch A.return_five to make it optionally consult the
instance, or you can assign to instance's __class__ to make it point to
a subclass of A that implements a different 'return_five'. Both options
are fairly unpleasant, but I think I'd go with the first one.

Others have spelled out the __class__-changing variant. While
monkey-patching is not the cleanest of practices to adopt, in my mind it
still beats assigning to __class__. Here is an example:

# Wrap return_five so it supports per-instance customization, but
# without copy-pasting the original.
def wrap_return_five(orig):
@property
def wrapper(self):
if 'return_five' in self.__dict__:
return self.__dict__['return_five']
return orig.__get__(self, type(self))
return wrapper
A.return_five = wrap_return_five(A.return_five)
a = A()
b = A()
a.return_five 5
a.__dict__['return_five'] = 10
a.return_five 10
b.return_five
5

If you want, you can make a.return_five itself settable, but I'll leave
that as an excercise for the reader.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top