'self' disappearing

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Daniel Nouri

    #1

    '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.metho d()' is not the same as
    'klass.method(i nstance)' 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(objec t):
    for (name, obj) in object.__dict__ .items():
    mytype = type(obj)

    if mytype in (types.Function Type, types.UnboundMe thodType):
    wrapper = FunWrapper(obj)
    object.__dict__[name] = wrapper

    elif mytype in (types.ModuleTy pe, types.ClassType ):
    _traverse(obj)


    def seque(module, fun):
    _traverse(modul e)
    module.__dict__[fun]()


    if __name__ == '__main__':
    import bla
    seque(bla, 'main')
  • Daniel Nouri

    #2
    Re: 'self' disappearing

    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(*arg s, **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.

    Comment

    • Steven Taschuk

      #3
      Re: 'self' disappearing

      Quoth Daniel Nouri:[color=blue]
      > 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.[/color]
      [...][color=blue]
      > It appears that 'instance.metho d()' is not the same as
      > 'klass.method(i nstance)' in this case. But why? And how do I deal with
      > that?[/color]

      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(obje ct):
      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__(*a rgs))

      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 staschuk@telusp lanet.net
      "I may be wrong but I'm positive." -- _Friday_, Robert A. Heinlein

      Comment

      Working...