В Python есть ли хороший способ применить декоратор (или нечто подобное) не к целой функции, а к подсегменту тела функции?
То, что я хочу, может выглядеть примерно так:
def deco_double(f):
def wrapper():
f()
f()
return wrapper
def foo():
@deco_double:
print("hello")
print("stack")
@deco_double:
print("overflow")
foo()
Таким образом, результат выполнения будет выглядеть следующим образом:
hello
stack
hello
stack
overflow
overflow
Это нормально, если решение не является точно декортером, мне нужен метод обертки функциональных подсегментов, но в абстрактном виде. Заранее спасибо :)
edit: Простое разделение на несколько функций для меня не является вариантом. Я разрабатываю рамки для программистов, и я хочу, чтобы они записывали функции в компактном виде (для написания foo() в примере. Кроме того, то, что я на самом деле делаю, намного сложнее, чем просто повторения)
edit2: Похоже, у меня нет выбора, кроме как ожидать, что пользователи инфраструктуры каким-то образом объявят именованные функции...
Органы функций скомпилированы в один "кодовый" объект, который запускается в целом, - изменяя способ запуска этого объекта кода, вставляя в него вещи, и такие вещи могут быть такими же сложными, как сам код языка (то есть код что фактически "исполняет" байт-код Python).
Таким образом, любые изменения в потоке выполнения намного проще сделать, используя инструкции на языке, который уже делает это.
Если вы хотите получить эквивалент общего декоратора по частям внутри тела функции, проще всего это разделить эту функцию на внутренние функции, а затем вы можете применить свои преобразования или выполнить каждую часть более одного раза, просто позвонив эти функции (и даже украсить их напрямую).
Однако, в случае, вы приносите в вашем вопросе, вы можете, и, вероятно, следует просто использовать обычный старый for
цикла:
def foo():
for _ in (0, 1):
print("hello")
print("stack")
for _ in (0, 1):
print("overflow")
Для произвольного "поведения декоратора", как я писал выше, просто используйте вложенные функции:
def foo():
@deco_double
def part1()
print("hello")
print("stack")
part1()
@deco_double:
def part2():
print("overflow")
part2()
Просто объявите две функции с любым именем с декоратором @deco_double
и вызовите их в любой другой функции, в вашем случае foo()
а затем просто вызовите foo()
.
def deco_double(f):
def wrapper():
f()
f()
return wrapper
@deco_double
def func1():
print("hello")
print("stack")
@deco_double
def func2():
print("overflow")
def foo():
func1()
func2()
foo()
Вывод этого кода.
hello
stack
hello
stack
overflow
overflow
Вам, вероятно, понадобится передать функции, используя lambda
если вы хотите достичь этого:
def doubler(f):
f()
f()
def foo():
doubler(lambda: print("hello"))
doubler(lambda: print("world"))
foo()
"hello"
"hello"
"world"
"world"
Оберните код, который вы хотите дважды запустить в lambda
, и передайте функцию doubler
Вам нужно будет извлечь эту частичную функциональность foo()
для разделения функций, а затем применить декоратор как функцию и называть его истечением.
def deco_double(f):
def wrapper():
f()
f()
return wrapper
def my_f1():
print("hello")
print("stack")
def my_f2():
print("overflow")
def foo():
deco_double(my_f1)()
deco_double(my_f2)()
foo()