чём проблема в обычную, не замкающуюся функцию взять, передать туда функцию и всё это дело выполнить
потому что не получится без замыкания использовать суть декоратора -то, что вызов функции не меняется, от того, что на нее навешан декоратор, а функционал изменяется. т.е. грубо говоря была у тебя функция: def bar(*args, **kwargs): pass а потом навесил на нее декоратор: @foo def bar(*args, **kwargs): pass и вот ты ее вызывал bar() до того как ее задекорировал и задекорировання она тоже вызывается как bar() а функционал у нее поменялся в зависимости от того, как его модифицировал декоратор
Не обязательны на самом деле
Все в реальности сложнее https://t.me/advice17/47
Всё равно не понимаю. Почему декоратор не может просто взять, как в данном случае, и import time def timer(func): start = time.time() func() end = time.time() return end - start def someone_func(): time.sleep(2) передать функцию someone_func() в timer()? В чём проблема?
А как реализовать декоратор без замыкания?
Например с functools.partial() Алсо подозреваю что там замыкание под капотом
мм и что же по ссылке сложнее? то что могут быть декораторы отличающиеся от паттерна "Декоратор" ?)
Или просто вернуть функцию без изменений. В питоне декоратор это не только паттерн декоратор, но ещё используется чтобы где-то зарегистрировать функцию
Ну я имею ввиду конкретно то, что ставится через @
def reg(func): registry.register(func) return func @reg def foo():…
Например как во фласке ты создаёшь эндпоинты
ну в примере который написали что делать если в функцию надо передать аргументы? городить прием в нее не только функции но и аргументов и вызов внутри с аргументами? в итоге оно будет работать, но вызывать надо будет именно функцию-таймер декоратор позволяет гибко настраивать функционал - захотели навесить декоратор дополнительно - навесили, не нужен больше - убрали, все изменения - в одном месте
*функциональность
import time def timer(func, *args, **kwargs): start = time.time() func(*args, **kwargs) end = time.time() return end def someone_func(*args, **kwargs): time.sleep(2) Т.е. я правильно понимаю, вы это имеете ввиду? Так всё равно же в замыкании функции которую мы вызываем также надо передать аргументы, предварительно их передав в подфункцию
Не знаю что такое registry, но смею предположить то это тоже самое замыкание. Т.е. замыкание есть, но неявное
То что декоратор может вернуть совсем другую фигню или ту же функцию
Что значит замыкающаяся / не замыкающаяся функции, можно примеры?
да, так я еще раз повторю: декоратор позволит более гибко управлять поведением функции (включать/выключать декорирование) с меньшими затратами сил
https://www.youtube.com/watch?v=sJF7OMNgLUs Кратко говоря - функция, которая возвращает функцию. К возвращённой функции можно обращаться используя имена из основной, ибо основная не удаляется сборщиком мусора, ибо на неё ссылаются
Это пример. Суть в том что ты регистрируешь функцию и возвращаешь ее же без изменений
Да! Я вас понимаю, но вопрос в том, почему блин декоратор использует именно замыкание? Он не может в обычную функцию запихать декорируемую и там её выполнить? Вот в чём непонятки
"Он не может в обычную функцию запихать декорируемую и там её выполнить?" как это может выглядеть (Если на псевдокоде)?
Выше скидывал код timer()
Давай проясним. В какой момент вызывается код декоратора?
В тот момент когда вызывается функция
Нет. Сразу после того как функция появилась в памяти
Каждый конкретный декоратор может использовать или не использовать замыкание. Часто исходя из того, что мы пишем, он генерирует новую функцию и нужен доступ к аргументу самого декоратора (оригинальной функции) - это и есть замыкание. Но это можно реализовать и другими способами (например, через partial или классы). А иногда это вообще не нужно
Нужен доступ к аргументу самого декоратора? Но в декоратор, же обычно передаётся только сама функция, а аргументы уже в подфункции. В каком случае передаются аргументы в оригинальную функцию?
Я же написал, доступ к оригинальной функции, щас поправлю формадировку
могут передаваться аргументы для работы самого декоратора например декоратор с пробросом аргумента для ретраев вызова функции )
стоит дотошно разобраться в теме, тогда большая часть "магии" в декораторах пропадет) вот тут неплохая статья https://habr.com/ru/articles/141411/ а у Балакирева на selfedu замыкания и декораторы разобраны с примерами и схемами, должно помочь
Да, вот именно что я учился по selfedu
ну тогда как минимум то что происходит внутри замыкания должно быть понятно, но кажется стоит внимательно пересмотреть. и начать именно с замыканий, чтобы четко понимать - в какой момент происходит замыкание, что именно "замыкается" в сохраненной локальной области видимости и как оно вообще работает
Да, вот в замыканиях я вполне себе разобрался. Что-то ссылается на подфункцию, а раз что-то ссылается на подфункцию, сборщик мусора не трогает саму функцию. Ну а раз сборщик мусора не трогает саму функцию, нам доступны её имена и мы можем с ними чо угодно делать
А можно псевдопример, генерации новой функции? И ещё вопрос: использует или не использует замыкание - подразумевается, использует или не использует ту внешнюю область (т.е. область основной функции, не убираемой сборщиком)?
def func_generator(a): def inner_function(): print(a) return inner_function вот тебе генератор функции с замыканием
Почему генератор? Это же же функция с замыканием, которая просто возвращает подфункцию, на которую можно ссылаться
https://stackoverflow.com/questions/2497801/closures-are-poor-mans-objects-and-vice-versa-what-does-this-mean 😛
в общем я подумал, мне кажется вопрос в принципе поставлен неверно. и дело не в замыкании, а в том что мы должны вернуть новую функцию. в примерах с таймером мы вызываем timer, передавая ему нужную функцию. а в питоновских декораторах вызов декоратора имеет ту же сигнатуру, что и вызов функции, мне кажется именно в этом причина использования внутр. функции, которую возвращаем (чтобы можно было присвоить переменной, хранящей начальную ф-цию. и вызывать в тех же местах), а не в замыкании
Обсуждают сегодня