Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #15108 > unrolled thread

How to mix-in __getattr__ after the fact?

Started bydhyams <dhyams@gmail.com>
First post2011-10-28 10:34 -0700
Last post2011-11-08 11:21 +0100
Articles 9 — 7 participants

Back to article view | Back to comp.lang.python


Contents

  How to mix-in __getattr__ after the fact? dhyams <dhyams@gmail.com> - 2011-10-28 10:34 -0700
    Re: How to mix-in __getattr__ after the fact? Jerry Hill <malaclypse2@gmail.com> - 2011-10-28 14:14 -0400
    Re: How to mix-in __getattr__ after the fact? Ethan Furman <ethan@stoneleaf.us> - 2011-10-28 11:20 -0700
    Re: How to mix-in __getattr__ after the fact? Lie Ryan <lie.1296@gmail.com> - 2011-10-29 13:26 +1100
      Re: How to mix-in __getattr__ after the fact? dhyams <dhyams@gmail.com> - 2011-10-31 05:01 -0700
        Re: How to mix-in __getattr__ after the fact? DevPlayer <devplayer@gmail.com> - 2011-11-01 22:50 -0700
        Re: How to mix-in __getattr__ after the fact? Lie Ryan <lie.1296@gmail.com> - 2011-11-08 15:17 +1100
          Re: How to mix-in __getattr__ after the fact? Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-11-08 05:58 +0000
        Re: How to mix-in __getattr__ after the fact? Thomas Rachel <nutznetz-0c1b6768-bfa9-48d5-a470-7603bd3aa915@spamschutz.glglgl.de> - 2011-11-08 11:21 +0100

#15108 — How to mix-in __getattr__ after the fact?

Fromdhyams <dhyams@gmail.com>
Date2011-10-28 10:34 -0700
SubjectHow to mix-in __getattr__ after the fact?
Message-ID<4630c4d0-86bc-4295-8bbb-6f58415191c8@v15g2000vbm.googlegroups.com>
Python 2.7.2

I'm having trouble in a situation where I need to mix-in the
functionality of __getattr__ after the object has already been
created.  Here is a small sample script of the situation:

=============snip

import types

class Cow(object):
  pass
  # this __getattr__ works as advertised.
  #def __getattr__(self,a):
  #   print "CAUGHT INCLASS: Attempting to get attribute ",a


def attrgetter(self,a):
   print "CAUGHT: Attempting to get attribute ",a

bessie = Cow()

bessie.__getattr__ = types.MethodType(attrgetter,bessie,Cow)

# here, I should see my printout "attempting to get attribute"
# but I get an AttributeException
print bessie.milk
======================snip

If I call __getattr__ directly, as in bessie.__getattr__('foo'), it
works as it should obviously; so the method is bound and ready to be
called.  But Python does not seem to want to call __getattr__
appropriately if I mix it in after the object is already created.  Is
there a workaround, or am I doing something wrongly?

Thanks,

[toc] | [next] | [standalone]


#15111

FromJerry Hill <malaclypse2@gmail.com>
Date2011-10-28 14:14 -0400
Message-ID<mailman.2289.1319825678.27778.python-list@python.org>
In reply to#15108
On Fri, Oct 28, 2011 at 1:34 PM, dhyams <dhyams@gmail.com> wrote:
> If I call __getattr__ directly, as in bessie.__getattr__('foo'), it
> works as it should obviously; so the method is bound and ready to be
> called.  But Python does not seem to want to call __getattr__
> appropriately if I mix it in after the object is already created.  Is
> there a workaround, or am I doing something wrongly?

Python looks up special methods on the class, not the instance (see
http://docs.python.org/reference/datamodel.html#special-method-lookup-for-new-style-classes).

It seems like you ought to be able to delegate the special attribute
access from the class to the instance somehow, but I couldn't figure
out how to do it in a few minutes of fiddling at the interpreter.

-- 
Jerry

[toc] | [prev] | [next] | [standalone]


#15112

FromEthan Furman <ethan@stoneleaf.us>
Date2011-10-28 11:20 -0700
Message-ID<mailman.2290.1319825995.27778.python-list@python.org>
In reply to#15108
dhyams wrote:
> Python 2.7.2
> 
> I'm having trouble in a situation where I need to mix-in the
> functionality of __getattr__ after the object has already been
> created.  Here is a small sample script of the situation:
> 
> =============snip
> 
> import types
> 
> class Cow(object):
>   pass
>   # this __getattr__ works as advertised.
>   #def __getattr__(self,a):
>   #   print "CAUGHT INCLASS: Attempting to get attribute ",a
> 
> 
> def attrgetter(self,a):
>    print "CAUGHT: Attempting to get attribute ",a
> 
> bessie = Cow()
> 
> bessie.__getattr__ = types.MethodType(attrgetter,bessie,Cow)
> 
> # here, I should see my printout "attempting to get attribute"
> # but I get an AttributeException
> print bessie.milk
> ======================snip
> 
> If I call __getattr__ directly, as in bessie.__getattr__('foo'), it
> works as it should obviously; so the method is bound and ready to be
> called.  But Python does not seem to want to call __getattr__
> appropriately if I mix it in after the object is already created.  Is
> there a workaround, or am I doing something wrongly?
> 
> Thanks,

Python only looks up __xxx__ methods in new-style classes on the class 
itself, not on the instances.

So this works:

8<----------------------------------------------------------------
class Cow(object):
   pass

def attrgetter(self, a):
    print "CAUGHT: Attempting to get attribute", a

bessie = Cow()

Cow.__getattr__ = attrgetter

print bessie.milk
8<----------------------------------------------------------------

~Ethan~

[toc] | [prev] | [next] | [standalone]


#15126

FromLie Ryan <lie.1296@gmail.com>
Date2011-10-29 13:26 +1100
Message-ID<mailman.2298.1319855210.27778.python-list@python.org>
In reply to#15108
On 10/29/2011 05:20 AM, Ethan Furman wrote:
>
> Python only looks up __xxx__ methods in new-style classes on the class
> itself, not on the instances.
>
> So this works:
>
> 8<----------------------------------------------------------------
> class Cow(object):
> pass
>
> def attrgetter(self, a):
> print "CAUGHT: Attempting to get attribute", a
>
> bessie = Cow()
>
> Cow.__getattr__ = attrgetter
>
> print bessie.milk
> 8<----------------------------------------------------------------

a minor modification might be useful:

bessie = Cow()
bessie.__class__.__getattr__ = attrgetter

[toc] | [prev] | [next] | [standalone]


#15168

Fromdhyams <dhyams@gmail.com>
Date2011-10-31 05:01 -0700
Message-ID<8bc11029-860e-4d3a-8770-062e16e31514@j39g2000yqc.googlegroups.com>
In reply to#15126
Thanks for all of the responses; everyone was exactly correct, and
obeying the binding rules for special methods did work in the example
above.  Unfortunately, I only have read-only access to the class
itself (it was a VTK class wrapped with SWIG), so I had to find
another way to accomplish what I was after.

On Oct 28, 10:26 pm, Lie Ryan <lie.1...@gmail.com> wrote:
> On 10/29/2011 05:20 AM, Ethan Furman wrote:
>
>
>
>
>
>
>
>
>
>
>
> > Python only looks up __xxx__ methods in new-style classes on the class
> > itself, not on the instances.
>
> > So this works:
>
> > 8<----------------------------------------------------------------
> > class Cow(object):
> > pass
>
> > def attrgetter(self, a):
> > print "CAUGHT: Attempting to get attribute", a
>
> > bessie = Cow()
>
> > Cow.__getattr__ = attrgetter
>
> > print bessie.milk
> > 8<----------------------------------------------------------------
>
> a minor modification might be useful:
>
> bessie = Cow()
> bessie.__class__.__getattr__ = attrgetter

[toc] | [prev] | [next] | [standalone]


#15255

FromDevPlayer <devplayer@gmail.com>
Date2011-11-01 22:50 -0700
Message-ID<a66161ab-7f86-43da-840e-c159ea4390f5@v8g2000vbe.googlegroups.com>
In reply to#15168
On Oct 31, 8:01 am, dhyams <dhy...@gmail.com> wrote:
> Thanks for all of the responses; everyone was exactly correct, and
> obeying the binding rules for special methods did work in the example
> above.  Unfortunately, I only have read-only access to the class
> itself (it was a VTK class wrapped with SWIG), so I had to find
> another way to accomplish what I was after.
>
Please share what you found as the other way.

[toc] | [prev] | [next] | [standalone]


#15450

FromLie Ryan <lie.1296@gmail.com>
Date2011-11-08 15:17 +1100
Message-ID<mailman.2529.1320725851.27778.python-list@python.org>
In reply to#15168
On 10/31/2011 11:01 PM, dhyams wrote:
>
> Thanks for all of the responses; everyone was exactly correct, and
> obeying the binding rules for special methods did work in the example
> above.  Unfortunately, I only have read-only access to the class
> itself (it was a VTK class wrapped with SWIG), so I had to find
> another way to accomplish what I was after.
>

As a big huge hack, you can always write a wrapper class:

class Wrapper(object):
     def __init__(self, *args, **kwargs):
         self.__object = MySWIGClass(*args, **kwargs)
     def __getattr__(self, attr):
         try:
             return getattr(self.__object, attr)
         except AttributeError:
             ...

[toc] | [prev] | [next] | [standalone]


#15457

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2011-11-08 05:58 +0000
Message-ID<4eb8c4f9$0$29988$c3e8da3$5496439d@news.astraweb.com>
In reply to#15450
On Tue, 08 Nov 2011 15:17:14 +1100, Lie Ryan wrote:

> On 10/31/2011 11:01 PM, dhyams wrote:
>>
>> Thanks for all of the responses; everyone was exactly correct, and
>> obeying the binding rules for special methods did work in the example
>> above.  Unfortunately, I only have read-only access to the class itself
>> (it was a VTK class wrapped with SWIG), so I had to find another way to
>> accomplish what I was after.
>>
>>
> As a big huge hack, you can always write a wrapper class:
> 
> class Wrapper(object):
>      def __init__(self, *args, **kwargs):
>          self.__object = MySWIGClass(*args, **kwargs)
>      def __getattr__(self, attr):
>          try:
>              return getattr(self.__object, attr)
>          except AttributeError:
>              ...


That's not a hack, that's a well-respected design pattern called 
Delegation.

http://rosettacode.org/wiki/Delegate
http://en.wikipedia.org/wiki/Delegation_pattern


In this case, you've implemented about half of automatic delegation:

http://code.activestate.com/recipes/52295

which used to be much more important in Python prior to the type/class 
unification in version 2.2.


To also delegate special dunder methods using new-style classes, see this:

http://code.activestate.com/recipes/252151



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#15712

FromThomas Rachel <nutznetz-0c1b6768-bfa9-48d5-a470-7603bd3aa915@spamschutz.glglgl.de>
Date2011-11-08 11:21 +0100
Message-ID<j9avrr$lj5$1@r03.glglgl.gl>
In reply to#15168
Am 31.10.2011 13:01 schrieb dhyams:
>
> Thanks for all of the responses; everyone was exactly correct, and
> obeying the binding rules for special methods did work in the example
> above.  Unfortunately, I only have read-only access to the class
> itself (it was a VTK class wrapped with SWIG), so I had to find
> another way to accomplish what I was after.

You could subclass the original class.

def newcow(attrgetter):
     class TmpCow(Cow):
         __getattr__ = attrgetter
     return TmpCow()

creates a new class for every instance.

class TmpCow(Cow):
     def __getattr__(self, attr):
         if hasattr(self, 'attr'):
             return getattr(self, 'attr')(attr)
         raise AttributeError # or somthing like that


If the creation of the object is outside your control, these 2 won't work.


Thomas

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web