properties and formatting with self.__dict__

Andrew Bennetts andrew-pythonlist at puzzling.org
Fri Feb 21 22:10:51 EST 2003


On Fri, Feb 21, 2003 at 07:56:40PM +0000, Alex Martelli wrote:
> <posted & mailed>
> 
> Andrew Bennetts wrote:
>    ...
> >> > You should write in the __init__ method something like
> >> > 
> >> > "self.full_name=property(self.get_full_name)"
>    ...
> >>   Except that, unfortunately, properties won't work as instance
> >>   attributes,
> >> only as class attributes.
> > 
> > I think you could fairly easily write your own instanceproperty that did
> > work with instances, though.
> 
> Could you?  Maybe I'm having a blind spot, but, without having a
> custom metaclass (redefining __getattribute__ differently from the
> implementation in object), how would you do it?  I.e. how would you
> code a type instanceproperty such that:
> 
> 
> class UIP(object):
> 
>     def getfullname(self): return 'Monty Python'
> 
>     def __init__(self):
>         self.fulname = instanceproperty(self.getfullname)
> 
> x = UIP()
> print x.fullname
> 
> 
> would result in x.getfullname() being _called_?  I just can't
> see how, and I'd like to learn -- thanks!

Hmm.  It's harder than I thought :)

I naïvely assumed that descriptors worked equally well for instances
as for classes, which turns out not to be true.  If it was, it would indeed
be fairly easy...

So I was wrong -- you'd have to define custom metaclass, or something along
those lines.  You could probably avoid a metaclass with something like:

    class C:
        def __init__(self, ...):
            instanceproperty(self, 'fullname', self.getfullname)

where instanceproperty was a function that inserted some sort of evil
descriptor into C.fullname if there wasn't already one... but it'd be worse
than simply defining __getattribute__ or __getattr__.

Hmm... maybe you could abuse metaclasses to return a freshly minted class
object instead of a mere instance, so that descriptors would work....

[experiments]

Ok, you could do it like this:

    >>> class instanceIsClass(object):
    ...     def __new__(cls):
    ...         class Instance(cls): pass
    ...         return Instance
    ... 
    >>> 
    >>> class C(instanceIsClass):
    ...     def __new__(self):
    ...         self.fullname = property(self.getfullname)
    ...         return object.__new__(self)
    ...     
    ...     def getfullname(self):
    ...         return 'Andrew Bennetts'
    ... 
    >>> c = C()
    >>> c.fullname
    'Andrew Bennetts'

Which isn't too far removed from:

    class C:
        def __init__(self):
            self.fullname = property(self.getfullname)

        def getfullname(self):
            return 'Andrew Bennetts'

Well, you'd have to stand a few metres back from the monitor and squint, but
then it kinda sorta looks similar <wink>.  Perhaps with a bit more
cleverness you could simplify my hack more.

Thanks for helping me realise that I'd assumed wrongly :)

-Andrew.






More information about the Python-list mailing list