Практический Python 3 для начинающих — КиберПедия 

Организация стока поверхностных вод: Наибольшее количество влаги на земном шаре испаряется с поверхности морей и океанов (88‰)...

Археология об основании Рима: Новые раскопки проясняют и такой острый дискуссионный вопрос, как дата самого возникновения Рима...

Практический Python 3 для начинающих

2023-02-03 24
Практический Python 3 для начинающих 0.00 из 5.00 0 оценок
Заказать работу

Декораторы

Практический Python 3 для начинающих

Теория и практика. Быстрая проверка задач и подсказки к ошибкам на русском языке. Работает в любом современном браузере.

НАЧАТЬ БЕСПЛАТНО LETPY.COM

Декораторы в Python и примеры их практического использования.

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

Вспомнив это, можно смело переходить к декораторам. Декораторы — это, по сути, "обёртки", которые дают нам возможность изменить поведение функции, не изменяя её код.

Создадимсвойдекоратор " вручную ":

>>>

>>>def my_shiny_new_decorator(function_to_decorate):

... # Внутри себя декоратор определяет функцию-"обёртку". Она будет обёрнута вокруг декорируемой,

... # получая возможность исполнять произвольный код до и после неё.

... def the_wrapper_around_the_original_function():

... print("Я - код, который отработает до вызова функции")

... function_to_decorate() # Самафункция

... print("А я - код, срабатывающий после")

... # Вернёмэтуфункцию

... return the_wrapper_around_the_original_function

...

>>> # Представим теперь, что у нас есть функция, которую мы не планируем больше трогать.

>>>def stand_alone_function():

... print("Я простая одинокая функция, ты ведь не посмеешь меня изменять?")

...

>>> stand_alone_function()

Я простая одинокая функция, ты ведь не посмеешь меня изменять?

>>> # Однако, чтобы изменить её поведение, мы можем декорировать её, то есть просто передать декоратору,

>>> # который обернет исходную функцию в любой код, который нам потребуется, и вернёт новую,

>>> # готовуюкиспользованиюфункцию :

>>> stand_alone_function_decorated = my_shiny_new_decorator(stand_alone_function)

>>> stand_alone_function_decorated()

Я - код, который отработает до вызова функции

Я простая одинокая функция, ты ведь не посмеешь меня изменять?

А я - код, срабатывающий после

Наверное, теперь мы бы хотели, чтобы каждый раз, во время вызова stand_alone_function, вместо неё вызывалась stand_alone_function_decorated. Дляэтогопростоперезапишем stand_alone_function:

>>>

>>> stand_alone_function = my_shiny_new_decorator(stand_alone_function)

>>> stand_alone_function()

Я - код, который отработает до вызова функции

Я простая одинокая функция, ты ведь не посмеешь меня изменять?

Я - код, который отработает до вызова функции

Оставь меня в покое

Print()

Func()

... print("<\______/>")

Return wrapper

...

>>>def ingredients(func):

... def wrapper():

... print("# помидоры #")

Func()

... print("~ салат ~")

Return wrapper

...

>>>def sandwich(food="-- ветчина --"):

... print(food)

...

>>> sandwich()

-- ветчина --

>>> sandwich = bread(ingredients(sandwich))

>>> sandwich()

#помидоры#

--ветчина--

~салат~

<\______/>

И используя синтаксис декораторов:

>>>

>>> @bread

... @ingredients

... def sandwich(food="-- ветчина --"):

... print(food)

...

>>> sandwich()

# помидоры #

-- ветчина --

~салат~

<\______/>

Также нужно помнить о том, что важен порядок декорирования. Сравните с предыдущим примером:

>>>

>>> @ingredients

... @bread

... def sandwich(food="-- ветчина --"):

... print(food)

...

>>> sandwich()

# помидоры #

-- ветчина --

<\______/>

~салат~

Меня зовут VasyaPupkin

Декорирование методов

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

>>>

>>>def method_friendly_decorator(method_to_decorate):

... def wrapper(self, lie):

... lie -= 3

... return method_to_decorate(self, lie)

Return wrapper

...

>>>classLucy :

... def __init__(self):

... self.age = 32

... @method_friendly_decorator

... def sayYourAge(self, lie):

... print(" Мне {} лет , атыбысколькодал ?".format(self.age + lie))

...

>>> l = Lucy()

>>> l.sayYourAge(-3)

Print(args)

Print(kwargs)

... function_to_decorate(*args, **kwargs)

... return a_wrapper_accepting_arbitrary_arguments

...

>>> @a_decorator_passing_arbitrary_arguments

... def function_with_no_argument():

... print("Python is cool, no argument here.")

...

>>> function_with_no_argument()

Передали ли мне что-нибудь?:

()

{}

1 2 3

>>> @a_decorator_passing_arbitrary_arguments

... def function_with_named_arguments(a, b, c, platypus=" Почемунет ?"):

... print("Любят ли{}, {}и {} утконосов? {} ".format(a, b, c, platypus))

...

>>> function_with_named_arguments(" Билл ", " Линус ", " Стив ", platypus=" Определенно !")

Передали ли мне что-нибудь?:

('Билл', 'Линус', 'Стив')

{'platypus':'Определенно!'}

Любят ли Билл, Линус и Стив утконосов? Определенно !

>>>classMary (object):

... def __init__(self):

... self.age = 31

... @a_decorator_passing_arbitrary_arguments

... def sayYourAge(self, lie=-3): # Теперь мы можем указать значение по умолчанию

... print("Мне {} лет, а ты бы сколько дал?".format(self.age + lie))

...

>>> m = Mary()

>>> m.sayYourAge()

Передали ли мне что-нибудь?:

(<__main__.Mary object at 0x7f6373017780>,)

{}

Декораторы с аргументами

А теперь попробуем написать декоратор, принимающий аргументы:

>>>

>>>def decorator_maker():

... print(" Ясоздаюдекораторы ! Я буду вызван только раз: когда ты попросишь меня создать декоратор.")

... def my_decorator(func):

... print(" Я - декоратор ! Я буду вызван только раз: в момент декорирования функции.")

... def wrapped():

... print ("Я - обёртка вокруг декорируемой функции.\n"

...                    "Я буду вызвана каждый раз, когда ты вызываешь декорируемую функцию.\n"

...                    "Я возвращаю результат работы декорируемой функции.")

Return func()

... print("Я возвращаю обёрнутую функцию.")

Return wrapped

... print("Я возвращаю декоратор.")

... return my_decorator

...

>>> # Давайте теперь создадим декоратор. Это всего лишь ещё один вызов функции

>>> new_decorator = decorator_maker()

Ясоздаюдекораторы ! Я буду вызван только раз: когда ты попросишь меня создать декоратор.

Я возвращаю декоратор.

>>>

>>> # Теперь декорируем функцию

>>>def decorated_function():

... print(" Я - декорируемаяфункция .")

...

>>> decorated_function = new_decorator(decorated_function)

Я - декоратор! Я буду вызван только раз: в момент декорирования функции.

Я - декорируемая функция.

Теперь перепишем данный код с помощью декораторов:

>>>

>>> @decorator_maker ()

... def decorated_function():

... print("Я - декорируемая функция.")

...

Я создаю декораторы! Я буду вызван только раз: когда ты попросишь меня создать декоратор.

Я возвращаю декоратор.

Я - декоратор! Я буду вызван только раз: в момент декорирования функции.

Я - декорируемая функция.

Вернёмся к аргументам декораторов, ведь, если мы используем функцию, чтобы создавать декораторы "на лету", мы можем передавать ей любые аргументы, верно?

>>>

>>>def decorator_maker_with_arguments(decorator_arg1, decorator_arg2):

... print("Я создаю декораторы! И я получил следующие аргументы:",

...            decorator_arg1, decorator_arg2)

... def my_decorator(func):

... print("Я - декоратор. И ты всё же смог передать мне эти аргументы:",

...                decorator_arg1, decorator_arg2)

... # Не перепутайте аргументы декораторов с аргументами функций!

... def wrapped(function_arg1, function_arg2):

... print ("Я - обёртка вокруг декорируемой функции.\n"

...                    "И я имею доступ ко всем аргументам\n"

...                    "\t- и декоратора: {0}{1}\n"

...                    "\t- и функции: {2}{3}\n"

...                    "Теперь я могу передать нужные аргументы дальше"

...                    .format(decorator_arg1, decorator_arg2,

...                            function_arg1, function_arg2))

... return func(function_arg1, function_arg2)

Return wrapped

... return my_decorator

...

>>> @decorator_maker_with_arguments ("Леонард", "Шелдон")

... def decorated_function_with_arguments(function_arg1, function_arg2):

... print ("Я - декорируемая функция и я знаю только о своих аргументах: {0}"

... " {1}".format(function_arg1, function_arg2))

...

Я создаю декораторы! И я получил следующие аргументы: Леонард Шелдон

Последняя проблема частично решена добавлением в модуле functools функции functools.wraps, копирующей всю информацию об оборачиваемой функции (её имя, из какого она модуля, её документацию и т.п.) в функцию-обёртку.

Foo

>>> # Однако, декораторы мешают нормальному ходу дел:

... def bar(func):

... def wrapper():

... print("bar")

Return func()

Return wrapper

...

>>> @bar

... def foo():

... print("foo")

...

>>> print(foo.__name__)

Wrapper

>>> importfunctools # "functools" можетнамсэтимпомочь

>>>def bar(func):

... # Объявляем "wrapper" оборачивающим "func"

... # и запускаем магию:

... @functools .wraps(func)

... def wrapper():

... print("bar")

Return func()

Return wrapper

...

>>> @bar

... def foo():

... print("foo")

...

>>> print(foo.__name__)

Foo

Примеры использования декораторов

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

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

>>>

>>>def benchmark(func):

... """

...     Декоратор, выводящий время, которое заняло

...     выполнение декорируемой функции.

...     """

Importtime

... def wrapper(*args, **kwargs):

...         t = time.clock()

... res = func(*args, **kwargs)

... print(func.__name__, time.clock() - t)

Return res

Return wrapper

...

>>>def logging(func):

... """

...     Декоратор, логирующий работу кода.

...     (хорошо, он просто выводит вызовы, но тут могло быть и логирование!)

...     """

... def wrapper(*args, **kwargs):

... res = func(*args, **kwargs)

... print(func.__name__, args, kwargs)

Return res

Return wrapper

...

>>>def counter(func):

... """

...     Декоратор, считающий и выводящий количество вызовов

...     декорируемой функции.

...     """

... def wrapper(*args, **kwargs):

... wrapper.count += 1

... res = func(*args, **kwargs)

... print("{0} былавызвана : {1}x".format(func.__name__, wrapper.count))

Return res

... wrapper.count = 0

Return wrapper

...

>>> @benchmark

... @logging

... @counter

... def reverse_string(string):

Wrapper 0.00011799999999997923

АрозА упал ан алапуазор А

>>> print(reverse_string("A man, a plan, a canoe, pasta, heros, rajahs, a coloratura,"

... "maps, snipe, percale, macaroni, a gag, a banana bag, a tan, a tag,"

... "a banana bag again (or a camel), a crepe, pins, Spam, a rut, a Rolo, cash,"

... "a jar, sore hats, a peon, a canal: Panama!"))

reverse_string былавызвана : 2x

wrapper ('A man, a plan, a canoe, pasta, heros, rajahs, a coloratura,maps, snipe, ...',) {}

Wrapper 0.00017800000000001148

!amanaP :lanac a ,noep a ,staheros ,raj a,hsac ,oloR a ,tur a ,mapS ,snip ,eperc a , ...


Интересно, зачем в этом примере в классе был конструктор __init__? :) Если всё работает и без него) Объясните, пожалуйста)) Я учусь!

Без __init__ значение age становится свойством класса. Таким образом изменив значение у класса (Lucy.age = 100) мы изменим его для всех экземпляров(как класса, так и потомков).
В данном примере это не играет роли, но при разработке ПО это может быть уязвимостью или источником багов.

А как работает подобный код? Никак не могу понять. То есть при обращению по адресу, который передается параметром в .route вызывается функция, идущая за ним следом? А название этой функции произвольно или нет? Она сама вызывается или там еще должен быть какой-то код?

@app.route('/')
defview_landing_page():
"""Generates Landing Page."""
tracking_enabled = 'HTTPBIN_TRACKING' in os.environ
return render_template('index.html', tracking_enabled=tracking_enabled)


@app.route('/html')
defview_html_page():
"""Simple Html Page"""

return render_template('moby.html')


@app.route('/robots.txt')
defview_robots_page():
"""Simple Html Page"""

response = make_response()
response.data = ROBOT_TXT
response.content_type = "text/plain"
return response


# ...
@app.route('/image/png')
defimage_png():
data = resource('images/pig_icon.png')
return Response(data, headers={'Content-Type': 'image/png'})


@app.route('/image/jpeg')
defimage_jpeg():
data = resource('images/jackal.jpg')
return Response(data, headers={'Content-Type': 'image/jpeg'})


Насколько я знаю это код Flask, где app это объект самого приложения. Получается у класса app, есть метод route, который принимает как аргумент строку адреса.
А далее что-то делает))

Код из этой статьи после
"Теперь перепишем данный код с помощью декораторов:"
дает ошибку при выполнении:

"decorator_maker() takes 0 positional arguments but 1 was given"

Неочевидный из статьи момент: при записи @decorator_maker() производится вызов функции и создается декоратор, который и применяется к написанной ниже функции.

При записи @decorator_maker - без скобок - вызов не производится, а производится при вызове декорируемой функции, что и порождает ошибку.

Запись @decorator_maker() должна быть со скобками. Запись @new_decorator - без.

Здравствуйте! Отличный сайт, все понятно, доходчиво. Я знаю возможности питона, есть много чего, узнал о pygame и тд. У меня вопрос: если я зазубрю эти 27 пунктов, это же не значит что я хотя бы на среднем уровне знаю питон? я бы хотел научится создавать сайты с помощью питона, это главное.

Декораторы

Практический Python 3 для начинающих


Поделиться с друзьями:

Поперечные профили набережных и береговой полосы: На городских территориях берегоукрепление проектируют с учетом технических и экономических требований, но особое значение придают эстетическим...

Биохимия спиртового брожения: Основу технологии получения пива составляет спиртовое брожение, - при котором сахар превращается...

Историки об Елизавете Петровне: Елизавета попала между двумя встречными культурными течениями, воспитывалась среди новых европейских веяний и преданий...

Таксономические единицы (категории) растений: Каждая система классификации состоит из определённых соподчиненных друг другу...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.139 с.