2.2 properties and subclasses

2 vues
Accéder directement au premier message non lu

Miles Egan

non lue,
19 mai 2003, 17:20:4319/05/2003
à
This prints "BASE" instead of "SUB". Is this right?

class BaseClass(object):
def __init__(self):
self._prop = "BASE"

def get_prop(self): return self._prop
prop = property(get_prop)

class SubClass(BaseClass):
def get_prop(self): return "SUB"

b = BaseClass()
print b.prop

s = SubClass()
print s.prop


--
miles egan
mi...@rddac.com

reverse the domain name to find me

OpenPGP/GPG Key 0x01F53D51 @ wwwkeys.us.pgp.net

Tim Peters

non lue,
19 mai 2003, 17:43:0819/05/2003
à
[Miles Egan]

> This prints "BASE" instead of "SUB". Is this right?

Yes.

> class BaseClass(object):
> def __init__(self):
> self._prop = "BASE"
>
> def get_prop(self): return self._prop
> prop = property(get_prop)
>
> class SubClass(BaseClass):
> def get_prop(self): return "SUB"

This overrides BaseClass.get_prop, but the class ends here and nothing gave
the name "prop" a new meaning in SubClass.

> b = BaseClass()
> print b.prop

Executes BaseClass.prop.

> s = SubClass()
> print s.prop

Also executes BaseClass.prop.

Add

prop = property(get_prop)

to the end of SubClass to get what I think you're trying to get. Note that
the

prop = property(get_prop)

lines are executed at class-definition time. Whatever value for get_prop is
current *when* the class is being defined is the value of get_prop used.
This isn't a "thunk" that looks up the value of get_prop at the time calls
are executed.

If you think that's what you want (I don't recommend it), you could, e.g.,
write the stuff this way instead:

class BaseClass(object):
def __init__(self):
self._prop = "BASE"

def get_prop(self): return self._prop
prop = property(lambda self: self.get_prop()) # the only change

class SubClass(BaseClass):
def get_prop(self): return "SUB"

Then the (still shared) prop dynamically looks up which get_prop() to use on
each invocation, and only get_prop needs to be overridden in SubClass.


Miles Egan

non lue,
19 mai 2003, 20:31:3819/05/2003
à
In article <mailman.105338073...@python.org>, Tim Peters wrote:
> [Miles Egan]

> If you think that's what you want (I don't recommend it), you could, e.g.,
> write the stuff this way instead:
>
> class BaseClass(object):
> def __init__(self):
> self._prop = "BASE"
>
> def get_prop(self): return self._prop
> prop = property(lambda self: self.get_prop()) # the only change
>
> class SubClass(BaseClass):
> def get_prop(self): return "SUB"
>
> Then the (still shared) prop dynamically looks up which get_prop() to use on
> each invocation, and only get_prop needs to be overridden in SubClass.

This is the behavior I was expecting. I guess what I really want here
is a simple way to implement properties in the base class and
intercept access to them in some cases in subclasses (lazy
initialization, etc).

Why don't you recommend this? It seems like a pretty natural solution
to my current problem.

Thanks for your help.

Tim Peters

non lue,
19 mai 2003, 20:49:3019/05/2003
à
[Tim]

> If you think that's what you want (I don't recommend it), you
> could, e.g., write the stuff this way instead:
>
> class BaseClass(object):
> def __init__(self):
> self._prop = "BASE"
>
> def get_prop(self): return self._prop
> prop = property(lambda self: self.get_prop()) # the only change
>
> class SubClass(BaseClass):
> def get_prop(self): return "SUB"
>
> Then the (still shared) prop dynamically looks up which
> get_prop() to use on each invocation, and only get_prop needs to be
> overridden in SubClass.

[Miles Egan]


> This is the behavior I was expecting. I guess what I really want here
> is a simple way to implement properties in the base class and
> intercept access to them in some cases in subclasses (lazy
> initialization, etc).
>
> Why don't you recommend this? It seems like a pretty natural solution
> to my current problem.

Just because it's clearer, and more efficient at runtime, to repeat

prop = property(get_prop)

in both classes. For that matter, it would be clearer and more efficient
still to have clients call get_prop() directly and skip the property layer,
but I appreciate that may be less convenient for clients. The two ways of
implementing with properties look the same to clients.


Miles Egan

non lue,
19 mai 2003, 22:17:0819/05/2003
à
In article <mailman.1053391949...@python.org>, Tim Peters wrote:
> [Miles Egan]
>> This is the behavior I was expecting. I guess what I really want here
>> is a simple way to implement properties in the base class and
>> intercept access to them in some cases in subclasses (lazy
>> initialization, etc).
>>
>> Why don't you recommend this? It seems like a pretty natural solution
>> to my current problem.
>
> Just because it's clearer, and more efficient at runtime, to repeat
>
> prop = property(get_prop)
>
> in both classes. For that matter, it would be clearer and more efficient
> still to have clients call get_prop() directly and skip the property layer,
> but I appreciate that may be less convenient for clients. The two ways of
> implementing with properties look the same to clients.

Repeating the property declaration for every property becomes painful
when you have a dozen classes with 10 properties each. There's
already a fair amount of boilerplate you have to write to set the
properties up in the base class.

Despite the inconvenience, I'd still much rather have properties than
not. The runtime overhead doesn't concern me much. If I were really
worried about function call overhead I wouldn't be using a scripting
langauge.

Just

non lue,
20 mai 2003, 03:53:0920/05/2003
à
In article <slrnbcj414...@car.pixar.com>,
Miles Egan <mi...@rddac.com> wrote:

> Repeating the property declaration for every property becomes painful
> when you have a dozen classes with 10 properties each. There's
> already a fair amount of boilerplate you have to write to set the
> properties up in the base class.

You could write a metaclass that automatically creates properties (say
using a naming convention):

class AutoProperty(type):
def __new__(cls, name, bases, methoddict):
for key, value in methoddict.items():
if key.startswith("get_"):
methoddict[key[4:]] = property(value)
return type.__new__(cls, name, bases, methoddict)


class Base(object):

__metaclass__ = AutoProperty

def get_foo(self):
return "BASE"


class Sub(Base):

def get_foo(self):
return "SUB"


b = Base()
print b.foo
s = Sub()
print s.foo


Just

Miles Egan

non lue,
20 mai 2003, 12:11:4820/05/2003
à
In article <just-AA3639.0...@news1.news.xs4all.nl>, Just wrote:
> In article <slrnbcj414...@car.pixar.com>,
> Miles Egan <mi...@rddac.com> wrote:
>
>> Repeating the property declaration for every property becomes painful
>> when you have a dozen classes with 10 properties each. There's
>> already a fair amount of boilerplate you have to write to set the
>> properties up in the base class.
>
> You could write a metaclass that automatically creates properties (say
> using a naming convention):
>
> class AutoProperty(type):
> def __new__(cls, name, bases, methoddict):
> for key, value in methoddict.items():
> if key.startswith("get_"):
> methoddict[key[4:]] = property(value)
> return type.__new__(cls, name, bases, methoddict)

That's an interesting idea. I haven't messed around with metaclasses
at all yet. Thanks for the suggestion.

Anton Muhin

non lue,
21 mai 2003, 14:07:0621/05/2003
à
Miles Egan wrote:
> This prints "BASE" instead of "SUB". Is this right?
>
> class BaseClass(object):
> def __init__(self):
> self._prop = "BASE"
>
> def get_prop(self): return self._prop
> prop = property(get_prop)
>
> class SubClass(BaseClass):
> def get_prop(self): return "SUB"
>
> b = BaseClass()
> print b.prop
>
> s = SubClass()
> print s.prop
>
>
Just my 2 cents:

PythonWin 2.2.1 (#34, Apr 15 2002, 09:51:39) [MSC 32 bit (Intel)] on win32.
Portions Copyright 1994-2001 Mark Hammond (mham...@skippinet.com.au) -
see 'Help/About PythonWin' for further copyright information.
>>> class BaseClass(object):
... def __init__(self):
... self._prop = "BASE"
... def get_property(self): return self._prop
... def __get_property__(self): return self.get_property()
... prop = property(__get_property__)
...
>>> class SubClass(BaseClass):
... def get_property(self): return "SUB"
...

>>> b = BaseClass()
>>> print b.prop

BASE


>>> s = SubClass()
>>> print s.prop

SUB
>>>

hth,
anton.

Répondre à tous
Répondre à l'auteur
Transférer
0 nouveau message