2016-07-07 6 views
-2

RANT - Почему люди говорят, что «декоратор - это функция, которая возвращает другую функцию»? Это определение не имеет смысла, потому что, если это все декоратор, почему бы вам просто не использовать вторую функцию, а не перенести с первым? - END RANTФормат декоратора в Python

К счастью, я нашел гораздо более разумное определение здесь: http://thecodeship.com/patterns/guide-to-python-function-decorators/

К сожалению, я до сих пор не понимаю примеры, как этот:

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)) 
    return func_wrapper 

my_get_text = p_decorate(get_text) 

print my_get_text("John") 

#Outputs "<p>lorem ipsum, John dolor sit amet</p>" 

Примечание, пост более двух лет, и авторы не ответили ни на один из комментариев.

Вот мой вопрос: почему не она выдавала

"<p>John</p>" 

или ошибка? Как вся строка попадает в теги p вместо имени?

+1

Вы вводите в заблуждение функцию и функцию, возвращаемую функцией. Декоратор может возвращать другую функцию в зависимости от того, какой аргумент (другая функция) задан. Он не вызывает функцию, которую он возвращает, но обычно возвращает функцию, * при вызове *, вызывает функцию, которая первоначально дана декоратору. – zondo

+1

По-видимому, вы не читали остальную часть этой статьи ... она объясняет в изнурительных подробностях, что именно происходит, каковы цели и как достичь этой цели, используя средства, предоставляемые python ... –

+0

@JeffMercado: Может быть, поэтому он упомянул эту статью как «более разумное определение» ... Он не сказал нам, какая статья для него не имеет смысла. – zondo

ответ

3

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, вы можете написать декоратор, чтобы обернуть класс и применить его к каждой функции автоматически для вас.

+0

Мне нужно посмотреть, могу ли я поместить это на свой собственный английский, чтобы узнать, понимаю ли вы вас: Возвращаем аргумент, (имя), завернутый в теги p, но делайте это в формате исходной функции get_text, поэтому результат полностью становится «lorem ipsum, John dolor sit amet» Таким образом, переменная {0} не заменяется и не перезаписывается, а «отформатирована», чтобы соответствовать исходной функции. Имеет ли это смысл? Это правильное объяснение на английском? –

+1

Я думаю, что я следую тому, что вы говорите, и если да, то да. '{0}' в get_text не влияет на '{0}' в 'func_wrapper'. Когда 'func_wrapper' вызывает' func (name) ', он возвращает строку' 'lorem ipsum, John dolor sit amet'', которая была создана путем форматирования' name' в '{0}' в 'get_text', а затем эта строка отформатирован в '{0}' в 'func_wrapper'. Итак, у вас есть '

(строка, возвращаемая get_text)

' возвращено 'func_wrapper' – Pythonista