Why is class decorator on method loosing self?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • c james

    Why is class decorator on method loosing self?

    I want to use the LRU decorator posted at

    on a class method. However, it complains about missing arguments. The
    missing argument is `self`. I could use @classmethod but what I really
    need is an instance method. I don't see how and was hoping someone else
    might know the way.

    Here is an example with taking that recipe as lru.py

    import lru

    class Foo(object):
    def banner(self):
    print "Testing method"

    @memoize(3)
    def min_max(self, sequence):
    self.banner()
    return min(sequence), max(sequence)

    foo = Foo()
    print foo.min_max([9,7,5,3,1])


    Traceback (most recent call last):
    ....
    File "lru.py", line 48, in __call__
    value = self.func(*args , **kwargs)
    TypeError: min_max() takes exactly 2 arguments (1 given)

  • George Sakkis

    #2
    Re: Why is class decorator on method loosing self?

    c james wrote:
    I want to use the LRU decorator posted at

    on a class method. However, it complains about missing arguments. The
    missing argument is `self`. I could use @classmethod but what I really
    need is an instance method. I don't see how and was hoping someone else
    might know the way.
    >
    Here is an example with taking that recipe as lru.py
    >
    import lru
    >
    class Foo(object):
    def banner(self):
    print "Testing method"
    >
    @memoize(3)
    def min_max(self, sequence):
    self.banner()
    return min(sequence), max(sequence)
    >
    foo = Foo()
    print foo.min_max([9,7,5,3,1])
    >
    >
    Traceback (most recent call last):
    ...
    File "lru.py", line 48, in __call__
    value = self.func(*args , **kwargs)
    TypeError: min_max() takes exactly 2 arguments (1 given)

    I don't think you can make it work without resorting to metaclass
    magic. At the point of decoration min_max is still a function, not a
    method, because class Foo has not been created yet. Here's a way to do
    it with a custom metaclass; whether you really want to do it is a
    different matter:

    First off, remove the decoratorargs class and have memoize inherit from
    object:

    class memoize(object) :
    # class body stays the same

    Then add the following:


    # this is general enough to be moved to a separate module
    class CustomizeMeta(t ype):
    def __init__(cls, name, bases,dict):
    for attr,val in dict.iteritems( ):
    if hasattr(val, '__customize'):
    setattr(cls, attr, getattr(val,'__ customize')(cls ))


    def memoizefunction (*args, **kwds):
    return lambda func: memoize(func, *args, **kwds)


    def memoizemethod(* args, **kwds):
    from types import MethodType
    def wrapper(func):
    func.__customiz e = lambda cls: \
    MethodType(memo ize(func,*args, **kwds), None, cls)
    return func
    return wrapper

    #==== examples =============== =============== ===============

    @memoizefunctio n(3)
    def fib(n):
    return (n 1) and (fib(n - 1) + fib(n - 2)) or 1


    class Foo(object):
    __metaclass__ = CustomizeMeta

    def __init__(self, i): self._i = i

    def banner(self):
    print "Testing method"

    @memoizemethod( 3)
    def min_max(self, sequence):
    self.banner()
    return min(sequence), max(sequence)

    foo = Foo()
    print foo.min_max([9,7,5,3,1])


    George

    Comment

    • c james

      #3
      Re: Why is class decorator on method loosing self?

      If I am reading this correctly you, are rebinding min_max in
      CustomizeMeta using '__customize' as the attribute to identify the
      member to work on.

      Thank you. I think you are right, this is probably the best way to
      implement what I intend for caching resource intensive processing.

      to George Sakkis wrote:
      >
      I don't think you can make it work without resorting to metaclass
      magic. At the point of decoration min_max is still a function, not a
      method, because class Foo has not been created yet. Here's a way to do
      it with a custom metaclass; whether you really want to do it is a
      different matter:
      >
      George
      >

      Comment

      • George Sakkis

        #4
        Re: Why is class decorator on method loosing self?

        George Sakkis wrote:
        I don't think you can make it work without resorting to metaclass
        magic. At the point of decoration min_max is still a function, not a
        method, because class Foo has not been created yet. Here's a way to do
        it with a custom metaclass; whether you really want to do it is a
        different matter:
        An improvement to my previous hack: leave memoize as is in the cookbook
        (extending decoratorargs) and add two lines to decoratorargs:

        # This would usually be defined elsewhere
        class decoratorargs(o bject):
        def __new__(typ, *attr_args, **attr_kwargs):
        def decorator(orig_ func):
        self = object.__new__( typ)
        self.__init__(o rig_func, *attr_args, **attr_kwargs)
        if callable(self):
        self._customize = lambda cls: MethodType(self , None,
        cls)
        return self
        return decorator

        Now you don't need memoizefunction and memoizemethod, but you still
        need the customized metaclass (changed __customize to _customize; name
        turns to a PITA sooner or later):

        class CustomizeMeta(t ype):
        def __init__(cls, name, bases,dict):
        for attr,val in dict.iteritems( ):
        if hasattr(val, '_customize'):
        setattr(cls, attr, val._customize( cls))


        #==== examples =============== =============== ===============

        @memoize(3)
        def fib(n):
        return (n 1) and (fib(n - 1) + fib(n - 2)) or 1

        class Foo(object):
        __metaclass__ = CustomizeMeta

        def __init__(self, i): self._i = i

        def banner(self):
        print "Testing method"

        @memoize(3)
        def min_max(self, sequence):
        self.banner()
        return min(sequence), max(sequence)

        foo = Foo()
        print foo.min_max([9,7,5,3,1])


        George

        Comment

        • George Sakkis

          #5
          Re: Why is class decorator on method loosing self?

          George Sakkis wrote:
          Now you don't need memoizefunction and memoizemethod, but you still
          need the customized metaclass (changed __customize to _customize; name
          turns to a PITA sooner or later):
          There was supposed to be a "mangling" after "name" (see, it's hard to
          even spell it out correctly, let alone use it <wink>).

          George

          Comment

          Working...