Edit: я просто понял, что ты была статья связана, что в буквальном смысле объясняет, что декораторы шаг за шагом ... но это уже отпечатал так ...
Там есть функция под названием закупорки/функция замыкания в Python ,
Прошло некоторое время с тех пор, как я попытался объяснить/понять, что происходит на более низком уровне с помощью затворов/декораторов, поэтому на самом деле это может быть неправильно.
Функция func_wrapper пересматривается каждый раз, когда p_decorate
называется, и func_wrapper будет помнить, что ограждающих пространство имен выглядит в момент определения.
Что это значит:
В качестве примера, скажем, вы были некоторые внешняя переменная вложена в p_decorate
вы бы ожидать, что это не вызовет ошибку, так как он больше не существует (это не локальный для func_wrapper), когда func_wrapper
называется и пытается использовать эту переменную, но это не так имен вшита «запоминается»
в Python 3 это __closure__
и питона 2 это func_closure
для ниже.
def get_text(name):
return "lorem ipsum, {0} dolor sit amet".format(name)
def p_decorate(func):
def func_wrapper(name):
return "<p>{0}</p>".format(func(name)) #Cached result
print(func_wrapper.func_closure)
return func_wrapper
my_get_text1 = p_decorate(get_text)
my_get_text2 = p_decorate(get_text2)
func_closure материал:
my_get_text1 >>> (<cell at 0x*: function object at 0x*>,)
my_get_text2 >>> (<cell at 0x(different address): function object at (diff address)>,)
Мы не передавая различные функции к функции func_wrapper
но строят собственные версии функции func_wrapper
, что «помнит», какую функцию он должен вызывать с помощью func
,
Если вы прошли в одной и той же функции дважды my_get_text1
и my_get_text2
вы бы точно такую же вещь для func_wrapper.func_closure
бит, адреса памяти и все для function object at *
, так как это та же функция. (Минус, когда вы на самом деле называете это потенциально другим аргументом.)
декораторы:
декоратор, как вы отметили, просто отзывной, которая принимает функцию в качестве аргумента и возвращает функцию замены. В вашем коде это будет p_decorator
и func_wrapper
соответственно.
Если вы хотите думать об этом в способе ООП ... Вы можете думать о p_decorate
как о конструкторе для функции func_wrapper
с func, действующим как переменная/атрибут частного члена, поскольку у вас есть более или менее встроенная функция с жестко закодированный аргумент func
.
Почему он возвращает то, что он делает:
Будем надеяться, что выше все правильно + имеет смысл ... Затем, она возвращает значение, которое вы видите, потому что вы прошли функцию get_text
, которая «запоминается» и так func_wrapper
возвращается ... Вы вызываете func_wrapper(arg)
с аргументом John
Теперь внутри этого ... func_wrapper
возвращает следующее:
"<p>{0}</p>".format(func(name))"
с func
быть get_text
. Так, get_text
называется возвращающий ...
"lorem ipsum, {0} dolor sit amet".format(name)
И тогда это отформатирован между открытием и закрытием p
тег, а затем вернулся.
У вас может быть несколько уровней вложенных функций, и, как и в любом случае, в python это черепахи полностью вниз.
Почему бы даже не использовать декораторы?
В этом примере я думаю, что вы правы, что я бы использовал вторую функцию, потому что это довольно бесполезный пример.
Но рассмотрите что-то более конкретное. Я использую обычный декоратор джанго в качестве примера с головы. Даже если вы не знакомы с Django, это все равно имеет смысл.
В django у вас есть функции/представления, которые отображают веб-страницы, и иногда вы можете потребовать, чтобы пользователь вошел в систему, чтобы просмотреть страницу.
Теперь, что если вы должны были написать пользовательскую логику для каждую функцию вы хотите это на.
Это было бы ужасно. Вместо этого есть отличный декоратор с именем @login_required
, который вы просто помещаете в начало функции, для которой вы хотите эту функцию, и вы просто сохранили тонну времени/дублированный код, потому что этот декоратор обертывает эту настраиваемую логику вокруг функции, которую вы применили к ней ,
Декораторы в основном полезны, когда вы хотите расширить/настроить функции без необходимости перекодировать все.
Идет даже дальше функций .... Что делать, если вы хотите применить это к методам class
. Может быть, все они или кто-то встречает определенные критерии?Было бы немного утомительно и потенциально раздражать, что нужно делать это для каждого отдельного метода. Вместо того, чтобы обертывать каждый метод с помощью @decorator_name
, вы можете написать декоратор, чтобы обернуть класс и применить его к каждой функции автоматически для вас.
Вы вводите в заблуждение функцию и функцию, возвращаемую функцией. Декоратор может возвращать другую функцию в зависимости от того, какой аргумент (другая функция) задан. Он не вызывает функцию, которую он возвращает, но обычно возвращает функцию, * при вызове *, вызывает функцию, которая первоначально дана декоратору. – zondo
По-видимому, вы не читали остальную часть этой статьи ... она объясняет в изнурительных подробностях, что именно происходит, каковы цели и как достичь этой цели, используя средства, предоставляемые python ... –
@JeffMercado: Может быть, поэтому он упомянул эту статью как «более разумное определение» ... Он не сказал нам, какая статья для него не имеет смысла. – zondo