3

I am a new hand for Python. When I learning decorator and class. There are something I totally dont understand

when we take a look an decorator example:

class Log_dec(object):

    def __init__(self, func):
        self.func = func
    def __call__(self, args):
        print('do something before function')
        Result=self.func(args)
        print(Result)
        print('do something after function')
@Log_dec
def myFunc(name):
    return 'My Name is %s'%name
myFunc('Haha')

Result is:

do something before function
My Name is Haha
do something after function

If we compare to another example:

class Log_dec(object):

    def __init__(self, func):
        self.func = func
    def __call__(self, args):
        print('do something before function')
        Result=self.func(args)
        print(Result)
        print('do something after function')
    def __CallTwice__(self,a_default_variable):
        print('do something different')
        Result_2=self.func(a_default_variable)
        print(Result_2)

@Log_dec
def myFunc(name):
    return 'My Name is %s'%name
myFunc('Haha')

Resuls is still:

do something before function
My Name is Haha
do something after function

It seems when we execute myFunc('Haha'), the function myFunc goes into func in the __init__ and the string Haha goes into args in the __call__.

My questions is, why the string Haha dont goes into a_defult_variable in the __CallTwice__??? That makes me confusced.

Or let's say, Why the function myFunc don't goes into a_default_variable in the __CallTwice__. Because I think apparently def __init__(self, func): has a same format as def __CallTwice__(self,a_default_variable): Does it?

lululu
  • 31
  • 2
  • 2
    Ignore the `@` syntax. What happens is `now = log(now)`. So `now` is now the `wrapper` function. Does that help? – timgeb Sep 10 '21 at 13:00
  • If 'now' is the 'wrapper', why we use 'return func(*args,**kw)' instead of 'return wrapper(*args,**kw)' ? – lululu Sep 10 '21 at 13:04
  • @lululu Infinite recursion, and then the original function `log` will be completely ignored, which is not what a decorator is for. – user2390182 Sep 10 '21 at 13:06
  • The task of `wrapper` is to call `func` (here: `func=now`) with arbitrary arguments and then do something in addition (here: `print` something). If you used `return wrapper(*args,**kw)` at the place of `return func(*args,**kw)` you would have infinite recursion where `wrapper` calls itself for all eternity. – timgeb Sep 10 '21 at 13:06
  • 1
    I assume you have noticed this: https://stackoverflow.com/questions/739654/how-to-make-function-decorators-and-chain-them-together/1594484#1594484 ? – moooeeeep Sep 10 '21 at 13:11
  • @timgeb Thank you for answer. I understand it will have infinite recursion when I do `return wrapper(*args,**kw)` , but I still dont get the point, why the variable x,y goes into the *args. See the second example, It's the same question, maybe clearly, why the function `myFunc` goes into the `func` and 'Haha' goes into the '*args' – lululu Sep 10 '21 at 13:15
  • @lululu I think you need to explain in a clearer way how it could/should be different. Do you know how starred and double-starred arguments work, e.g. `*args` and `**kwargs`? There are no special rules at work in your examples. – timgeb Sep 10 '21 at 13:18
  • @timgeb Thankyou for your suggestion. I changed my Question already. Would you like to give me some help? – lululu Sep 10 '21 at 13:38
  • I think you should consume the link by moooeeep and then come back. – timgeb Sep 10 '21 at 13:39
  • Your `__CallTwice__` method is not called anywhere in your code. Where do you expect it to be executed? – kaya3 Sep 10 '21 at 13:40
  • @timgeb Hallo, from my view `__CallTwice__` has the exactly same format as `__call__`, If the function `myFunc(name)` was executed on `Result=self.func(args)` , It should be also executed on `Result_2=self.func(a_default_variable)` as well. So from my understand, the results should be `do something before function My Name is Haha do something after function do something different My Name is Haha` – lululu Sep 10 '21 at 13:49

1 Answers1

3

This answer just rewrites your example with self-documenting names and without the @-syntax.

def create_new_function_from_existing_function(old_function): # def log
    def new_function(*some_positional_arguments, **some_keyword_arguments): # define wrapped function
        print('call %s:' % old_function.__name__)
        return old_function(*some_positional_arguments, **some_keyword_arguments)
    return new_function # return wrapped function

def now(x, y):
    print('2021-9-3 value=', x + y)

now = create_new_function_from_existing_function(now) # @log ...
Roman Pavelka
  • 3,736
  • 2
  • 11
  • 28
timgeb
  • 76,762
  • 20
  • 123
  • 145