Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #15108 > unrolled thread
| Started by | dhyams <dhyams@gmail.com> |
|---|---|
| First post | 2011-10-28 10:34 -0700 |
| Last post | 2011-11-08 11:21 +0100 |
| Articles | 9 — 7 participants |
Back to article view | Back to comp.lang.python
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
| From | dhyams <dhyams@gmail.com> |
|---|---|
| Date | 2011-10-28 10:34 -0700 |
| Subject | How 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]
| From | Jerry Hill <malaclypse2@gmail.com> |
|---|---|
| Date | 2011-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]
| From | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| Date | 2011-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]
| From | Lie Ryan <lie.1296@gmail.com> |
|---|---|
| Date | 2011-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]
| From | dhyams <dhyams@gmail.com> |
|---|---|
| Date | 2011-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]
| From | DevPlayer <devplayer@gmail.com> |
|---|---|
| Date | 2011-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]
| From | Lie Ryan <lie.1296@gmail.com> |
|---|---|
| Date | 2011-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]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2011-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]
| From | Thomas Rachel <nutznetz-0c1b6768-bfa9-48d5-a470-7603bd3aa915@spamschutz.glglgl.de> |
|---|---|
| Date | 2011-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