О декораторах в Python

Автор оригинала: Kibo Hutchinson
  • Перевод

Всем привет!


Перевод статьи подготовлен для студентов курса «Web-разработчик на Python». Интересно развиваться в данном направлении? Запишитесь на День Открытых Дверей курса и пообщайтесь вживую с преподавателем: онлайн-трансляция 23 июля в 20:00 по мск.!



Когда вы упражнялись в программировании на языке Python, вы, должно быть сталкивались с таким понятием, как декораторы. Они являются одним из самых элегантных и часто используемых инструментов в современных библиотеках и фреймворках. Декораторы — хороший способ инкапсулировать множество деталей реализации, оставляя на поверхности простой интерфейс.


Давайте рассмотрим пример простого декоратора логина, который проверяет, что пользователь вошел в систему, прежде чем давать ему возможности редактировать посты. Потом декоратор перенаправляет на страницу входа в систему или регистрации, а затем с помощью правильно заданных параметров возвращает обратно на ту же страницу после успешного прохождения идентификации. Чтобы воспользоваться данной функцией, вам нужно всего лишь написать @login_required перед целевой функцией.


@login_required
def edit_post(post_id):
...

С декораторами очень легко работать, но создание декораторов задача непростая даже для опытных Python-программистов. В этой статье мы с вами рассмотрим пошагово как работают декораторы в Python.


Функции


Функции также называются объектами первого класса в Python. Функции это такие же значения, как числа, списки и строки, как видно из следующего примера.


>>> def foo():
...     return 1
...
>>>
>>> foo()
1
>>>

У функций есть свое собственное пространство имен, где происходит поиск имен переменных в первую очередь, когда они встречаются в теле функции. Давайте напишем простую функцию, чтобы понять разницу между глобальной и локальной областью видимостью.


>>>
>>> a_string = "This is a global variable"
>>>
>>> def foo():
...     print(locals())
...
>>>
>>> print(globals())
{..., 'a_string': 'This is a global variable'}
>>>
>>> foo() # 2
{}
>>>

Область видимости функции как переменная


Правило области видимости в Python гласит, что при создании переменной всегда создается новая локальная переменная, но доступ к переменной определяется в локальной области видимости при поиске по всем ближайшим областям совпадений имен переменных. Это не значит, что мы не можем получить доступ к глобальным переменным из нашей функции. Чтобы выводить глобальную переменную мы изменим функцию foo следующим образом:


>>>
>>> a_string = "This is a global variable"
>>>
>>> def foo():
...     print(a_string) #1
...
>>>
>>> foo()
This is a global variable
>>>

Время жизни переменной


В пространстве имен живут не только переменные, но и они имеют время жизни, о котором важно помнить. Рассмотрим пример, который иллюстрирует не только правила области видимости и те проблемы, которые они могут вызвать, но и то, как они взаимодействуют с вызовом функции и то как они работают в Python и других языках.


>>> def foo():
...     x = 1
...
>>> foo()
>>>
>>> print(x) # 1
Traceback (most recent call last):
  ...
NameError: name 'x' is not defined
>>>

Вложенные функции


В Python можно создавать вложенные функции, а это значит, что мы можем объявлять функции внутри функций, и все правила области видимости и времени жизни по-прежнему действуют.


>>>
>>> def outer():
...     x = 1
...     def inner():
...         print(x) # 1
...     inner() # 2
...
>>> outer()
1
>>>

Декораторы


Замыкание (closure), которое принимает функцию в качестве параметра и возвращает функцию, называется декоратором. Рассмотрим пример полезных декораторов.


>>>
>>> def outer(some_func):
...     def inner():
...         print("before some_func")
...         ret = some_func() # 1
...         return ret + 1
...     return inner
...
>>> def foo():
...     return 1
...
>>> decorated = outer(foo) # 2
>>>
>>> decorated()
before some_func
2
>>>

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


>>>
>>> foo = outer(foo)
>>>
>>> foo # doctest: +ELLIPSIS
<function outer.<locals>.inner at 0x...>
>>>

Теперь для отслеживания вызовов функций у нас есть красивый декоратор. Декораторы могут использоваться для работы с любым языком программирования с помощью Python. Это крайне полезный инструмент, механизм работы которого необходимо понять, чтобы правильно их применять.

OTUS. Онлайн-образование
Цифровые навыки от ведущих экспертов

Комментарии 5

    +1
    За перевод спс, но все же есть и более подробные тексты
    1
    2
      +8

      cat /etc/crontab


      52 6    1 * *   root   post -mode article --topic 'python decorators'
      47 6    * * 7   root   post -mode article --topic 'javascript =='
      25 6    * * *   root   post -mode article --topic 'runnning your app in Dorker'
        0
        Про декораторы функций (и методов) всё пережёвано уже много раз.
        О декораторах классов бы статью.
          +4
          Cпасибо, все очень доступно написано. Ждем статью про присвоение значений переменным и создание своих классов!
            0
            но создание декораторов задача непростая даже для опытных Python-программистов

            Эм, это ж элементарщина. Особенно показанный в посте пример, когда декоратор даже никаких параметров не принимает

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое