property decorator and inheritance

L

Laurent

Hi. I couldn't find a way to overwrite a property declared using a decorator in a parent class. I can only do this if I use the "classic" property() method along with a getter function. Here's an example:

#!/usr/bin/python3

class Polite:

def __init__(self):
self._greeting = "Hello"

def get_greeting(self, suffix=", my dear."):
return self._greeting + suffix
greeting1 = property(get_greeting)

@property
def greeting2(self, suffix=", my dear."):
return self._greeting + suffix


class Rude(Polite):

@property
def greeting1(self):
return self.get_greeting(suffix=", stupid.")

@property
def greeting2(self):
return super().greeting2(suffix=", stupid.")


p = Polite()
r = Rude()

print("p.greeting1 =", p.greeting1)
print("p.greeting2 =", p.greeting2)
print("r.greeting1 =", r.greeting1)
print("r.greeting2 =", r.greeting2) # TypeError: 'str' object is not callable



In this example I can easily overwrite the greeting1 property. But the inherited greeting2 doesn't seem to be a property but a mere string.

I use a lot of properties decorators for simple properties in a project andI hate mixing them with a couple of "undecorated" properties that have to be overwritten in child classes. I tried using @greeting2.getter decorator and tricks like this but inheritance overwriting failed every time I used decorators.
Can someone tell me a way to use decorator-declared properties that can beoverwritten in child classes?? That would be nice.
 
A

alex23

Hi. I couldn't find a way to overwrite a property declared using a decorator in a parent class.
class Polite:
    @property
    def greeting2(self, suffix=", my dear."):
        return self._greeting + suffix

Here you set up greeting2 as a property.
class Rude(Polite):
    @property
    def greeting2(self):
        return super().greeting2(suffix=", stupid.")

Here you call Polite.greeting2 as a function.
print("r.greeting2 =", r.greeting2) # TypeError: 'str' object is not callable

And here it's telling you that you're trying to treat a string - the
output of Polite.greeting2 - as a function.

The problem isn't that you cannot override greeting2 on Rude, it's
that you can't treat properties as functions, so you can't pass in a
new suffix. Instead, break the suffix out as a class attribute, then
each descendent just needs to override that attribute:

class Polite(object):
suffix = ', my dear'

@property
def greeting(self):
return 'Hello' + self.suffix

class Rude(Polite):
suffix = ', stupid'
 
L

Laurent

Yes using a separate class variable would transfer the problem to the classlevel. But adding 10 class variables if I have 10 properties would be ugly.. Maybe I should reformulate the subject of this thread to "is there some python magic to pass parameters to decorator-declared properties ?"
 
O

OKB (not okblacke)

Laurent said:
Yes using a separate class variable would transfer the problem to
the class level. But adding 10 class variables if I have 10
properties would be ugly. Maybe I should reformulate the subject of
this thread to "is there some python magic to pass parameters to
decorator-declared properties ?"

You can't have it both ways. If you want

myObj.greeting2 # No parentheses

To evaluate to a string (which it will if it's a property as you
set it up), then it is necessarily true that myObj.greeting2(somearg) is
going to try to call that string, which isn't going to work. If you
need to be able to pass in parameters, then you need greeting2 to be a
real method, not a property, and you need to get the greeting string
with

myObj.greeting2() # Parentheses

All this is as it should be. The whole point of properties is that
outside functions accessing them don't "know" that a getter function is
called behind the scenes.

--
--OKB (not okblacke)
Brendan Barnwell
"Do not follow where the path may lead. Go, instead, where there is
no path, and leave a trail."
--author unknown
 
C

Chris Rebert

Yes using a separate class variable would transfer the problem to the class level. But adding 10 class variables if I have 10 properties would be ugly. Maybe I should reformulate the subject of this thread to "is there somepython magic to pass parameters to decorator-declared properties ?"

Apparently, yes:
.... @property
.... def bar(self, arg1='baz', arg2='qux'):
.... return arg1, arg2
....
Though I do not like this trick at all.

Cheers,
Chris
 
L

Laurent

Hey yes it's working that way. But I don't like it very much either. If as OKB said the whole point is that outside functions can't detect a property then I'm going to stick with the non-decorator way. Thanks anyway.
 
L

Laurent

Hey yes it's working that way. But I don't like it very much either. If as OKB said the whole point is that outside functions can't detect a property then I'm going to stick with the non-decorator way. Thanks anyway.
 

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

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top