-1

I am trying to understand the difference of returning a lambda vs a method in a decorator below. The calling object instance "o" is missing and not passed by the decorator when returning m.fm. The decorator will pass the instance while returning a lambda function. Is it possible to pass the calling object by returning a method in decorator?

def deco(*type):
    def wrapper(func):
        m = M()
        # return lambda callingobj, *args: m.fm(callingobj, *args)
        return m.fm
    return wrapper

class M(object):
    def fm(self, callingobj, *args):
        print(f'self_ {callingobj}, args {args}')

class O(object):
    @deco('int')
    def fo(self, *args):
        print(f'{args}')


o = O()
o.fo(1, 2, 3)

Output:

  1. with return lambda callingobj, *args: m.fm(callingobj, *args)

    callingobj <__main__.O object at 0x000002453BE95760>, args (1, 2, 3)

  2. with return m.fm

    callingobj 1, args (2, 3)

Bin Li
  • 3
  • 1

1 Answers1

0

With the lambda expression, the attribute O.fo is bound to a function object. When accessed, o.fo produces the value of O.fo.__get__(o, O), which is a method object that passes its arguments on to the function. That is, __get__ returns a function whose first parameter is callingobj, which gets bound to o. The remaining arguments are bound as a tuple (1, 2, 3) toargs`

With return m.fm, the attribute O.fo is bound to the method object produced by m.fm, which is equivalent to M.fm.__get__(m, M). Importantly, a method object has no __get__ method, so o.fo gives you the method of the M class directly. Now the arguments 1, 2, and 3 are assigned such that 1 is assigned to callingobj and (2, 3) is assigned to args.

In other words, the difference is the order in which some function's __get__ method relative to when the arguments to o.fo are processed.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • @chepener. Instead of `return m.fm`. I tried using `return m.fm.__func__` and get the same result. `m.fm.__func__` does have `__get__`. I actually tried to figure out if it is possible to use stack multimethod decorator from [this thread](https://stackoverflow.com/questions/48483650/python-lost-self-while-decorating-class-multimethods). Using lambda breaks stack of multiple multimethod decorator. – Bin Li Nov 20 '19 at 16:03