Я читал о том, что мы можем создать ссылку на любую функцию в Python, но я также читал, что при создании декоратора мы используем специальный синтаксис под названием "@": ex: @decorator_function и это @decorator_function равно new_function=decorator_function(new_function)

Так что мои сомнения на мой взгляд оба:

  1. anything = decorator_function(new_function)
  2. new_function=decorator_function(new_function)

Оба играют роль замыкания, но оба приводят к разным результатам. так в чем же разница между ними обоими?

Пример кода:

def deco(fn):
    def wrapper(*args):
        print('called')
        return fn(*args)

    return wrapper


def something(x):
    if x == 0:
        print('first')
        something(x+1)
    else:
        print('hello')


print('new name')
a = deco(something)
a(0)
print('\nreassigning to the same name')
something = deco(something)
something(0)
1
user8224771 26 Авг 2017 в 23:25

3 ответа

Лучший ответ

Для первого a = deco(something)

def deco(fn):
    def wrapper(*args):
        print('called') 
        return something(*args)      # Notice here
return wrapper 

Второй, something = deco(something) - это то же самое, что и , за исключением , и ваша исходная функция something теперь стала функцией wrapper, которую deco вернул.

>>> something
<function deco.<locals>.wrapper at 0x7fbae4622f28>
>>> a
<function deco.<locals>.wrapper at 0x7fbae4622ea0>

И something, и a оборачивают оригинал something до того, как он был переопределен назначением something = deco(something). Python внутренне сохранил оригинальную функцию something где-то в функциях-оболочках:

>>> something.__closure__[0].cell_contents
<function something at 0x7fbae4622bf8>

>>> a.__closure__[0].cell_contents
<function something at 0x7fbae4622bf8>

В последнем задании something стало что-то другое:

>>> something
<function deco.<locals>.wrapper at 0x7fbae4622f28>
1
direprobs 26 Авг 2017 в 20:49

Оба ваших задания, использующие ручные вызовы декоратору, работают. Но один из них (тот, который связывает something) заменяет исходную функцию, так что она больше не может быть достигнута по ее первоначальному имени. Это ничем не отличается от использования любого другого назначения. Например:

def foo(x):
    return x + 1

a = 10

a = foo(a)

Когда вы присваиваете результат foo(a) a, он заменяет старое значение 10 новым значением 11. Вы не можете получить 10 больше.

Синтаксис декоратора делает то же самое.

def deco(fn):
    def wrapper(*args):
        print('called')
        return fn(*args)

    return wrapper

def func_1(x):
    pass
func_1 = deco(func_1) # replace the old func_1 with a decorated version

@deco                 # the @ syntax does the same thing!
def func_2(x):
    pass

Не запрещено использовать декоратор для создания функции с другим именем, просто она обычно не так полезна (и поэтому для нее нет специального синтаксиса):

def func_3(x):
    pass

func_4 = deco(func_3) # this works, creating a new function name without hiding the old one
0
Blckknght 26 Авг 2017 в 20:44

Оригинальная функция something, которую вы написали, выполняет рекурсивный вызов something, а не a.

Если вы назначите deco(something) для a, то something по-прежнему будет исходной функцией, а рекурсивный вызов вызовет исходную функцию:

  • новая функция вызывает оригинальную функцию
  • оригинальная функция ищет something, находит оригинальную функцию
  • оригинальная функция вызывает оригинальную функцию ...

Если вы назначите deco(something) для something, то something теперь будет новой функцией, и рекурсивный вызов вызовет новую функцию:

  • новая функция вызывает оригинальную функцию
  • исходная функция ищет something, находит новую функцию
  • оригинальная функция вызывает новую функцию
  • новая функция вызывает оригинальную функцию ...
4
user2357112 supports Monica 26 Авг 2017 в 20:41