'self' disappearing

D

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.

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')
 
D

Daniel Nouri

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.
 
S

Steven Taschuk

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>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,077
Messages
2,570,566
Members
47,202
Latest member
misc.

Latest Threads

Top