468,136 Members | 1,441 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 468,136 developers. It's quick & easy.

'self' disappearing

The idea of my simple piece of code is to start from a given module and
wrap all functions and methods in that module and submodules. FunWrapper is
the class that I use for wrapping.

The last two calls of main() in module bla are of interest. While the first
'foo.bar(c)' works as expected, i.e. prints 'Hello from foo.bar' and
'Calling bar', the second call bails out with:

File "seque.py", line 9, in __call__
self.fun(*args, **kwds)
TypeError: bar() takes exactly 1 argument (0 given)

It appears that 'instance.method()' is not the same as
'klass.method(instance)' in this case. But why? And how do I deal with
that?
---bla.py---

def a():
print 'Hello from A'

def b():
print 'Hello from B'

class foo:

def bar(self):
print 'Hello from foo.bar'

def baz(self):
print 'Hello from foo.baz'

def main():
a()
b()
c = foo()
foo.bar(c) #works
c.bar() #raises TypeError (0 arguments given)

---seque.py---

import types

class FunWrapper:
def __init__(self, fun):
self.fun = fun

def __call__(self, *args, **kwds):
print 'Calling', self.fun.__name__
self.fun(*args, **kwds)

def _traverse(object):
for (name, obj) in object.__dict__.items():
mytype = type(obj)

if mytype in (types.FunctionType, types.UnboundMethodType):
wrapper = FunWrapper(obj)
object.__dict__[name] = wrapper

elif mytype in (types.ModuleType, types.ClassType):
_traverse(obj)
def seque(module, fun):
_traverse(module)
module.__dict__[fun]()
if __name__ == '__main__':
import bla
seque(bla, 'main')
Jul 18 '05 #1
2 1689
Answering my own question:
Only a class attribute that is of FunctionType will be automatically
converted into a bound method by the Python interpreter. If I wanted more
control, I would have to do it through metaclasses.

However, my (working) approach now is to return a function instead of a
class instance, using this simple closure:

def make_funwrapper(fun):
def funwrapper(*args, **kwds):
print 'Calling', fun.__name__
fun(*args, **kwds)

return funwrapper

Note that this requires Python 2.2 or 'from __future__ import
nested_scopes' because I'm using 'fun' in the nested function.
Jul 18 '05 #2
Quoth Daniel Nouri:
The idea of my simple piece of code is to start from a given module and
wrap all functions and methods in that module and submodules. FunWrapper is
the class that I use for wrapping. [...] It appears that 'instance.method()' is not the same as
'klass.method(instance)' in this case. But why? And how do I deal with
that?


Your function wrapper implements only the __call__ protocol; you
also need to handle the descriptor protocol, which is used to
implement the bound/unbound method business. For example:

class FunWrapper(object):
def __init__(self, fun):
self.fun = fun
def __call__(self, *args, **kwds):
print 'Calling', self.fun.__name__
self.fun(*args, **kwds)
def __get__(self, *args):
print 'Getting', self.fun.__name__
return FunWrapper(self.fun.__get__(*args))

class Foo(object):
def bar(*args):
print 'called with args', args
bar = FunWrapper(bar)

foo = Foo()
foo.bar('a', 'b', 'c')

You might find Raymond Hettinger's writeup of descriptors useful
to understand what's going on here:
<http://users.rcn.com/python/download/Descriptor.htm>

--
Steven Taschuk st******@telusplanet.net
"I may be wrong but I'm positive." -- _Friday_, Robert A. Heinlein

Jul 18 '05 #3

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

1 post views Thread by R0bert Neville | last post: by
1 post views Thread by .Net Sports | last post: by
2 posts views Thread by neptune | last post: by
2 posts views Thread by Rachel Suddeth | last post: by
reply views Thread by =?Utf-8?B?Q2hhcmxlcw==?= | last post: by
27 posts views Thread by didacticone | last post: by
1 post views Thread by gcdp | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.