런타임에 기능/메소드 데코레이터를 교체 할 수 있습니까? [파이썬
-
22-07-2019 - |
문제
기능이있는 경우 :
@aDecorator
def myfunc1():
# do something here
if __name__ = "__main__":
# this will call the function and will use the decorator @aDecorator
myfunc1()
# now I want the @aDecorator to be replaced with the decorator @otherDecorator
# so that when this code executes, the function no longer goes through
# @aDecorator, but instead through @otherDecorator. How can I do this?
myfunc1()
런타임에 데코레이터를 교체 할 수 있습니까?
해결책
데코레이터가 적용되면 "교체"하는 방법이 있는지 모르겠지만, 기능이 이미 변경 되었기 때문에 아마도 없을 것 같아요.
어쨌든 일부 조건에 따라 런타임에 데코레이터를 적용 할 수 있습니다.
#!/usr/bin/env python
class PrintCallInfo:
def __init__(self,f):
self.f = f
def __call__(self,*args,**kwargs):
print "-->",self.f.__name__,args,kwargs
r = self.f(*args,**kwargs)
print "<--",self.f.__name__,"returned: ",r
return r
# the condition to modify the function...
some_condition=True
def my_decorator(f):
if (some_condition): # modify the function
return PrintCallInfo(f)
else: # leave it as it is
return f
@my_decorator
def foo():
print "foo"
@my_decorator
def bar(s):
print "hello",s
return s
@my_decorator
def foobar(x=1,y=2):
print x,y
return x + y
foo()
bar("world")
foobar(y=5)
다른 팁
Miya가 언급했듯이, 해당 기능 선언에 도달하기 전에 데코레이터를 다른 기능으로 교체 할 수 있습니다. 그러나 일단 데코레이터가 함수에 적용되면 데코레이터를 다른 것으로 대체 할 수있는 방법이 없다고 생각합니다. 예를 들어 :
@aDecorator
def myfunc1():
pass
# Oops! I didn't want that decorator after all!
myfunc1 = bDecorator(myfunc1)
MyFunc1은 더 이상 원래 정의한 기능이 아니기 때문에 작동하지 않습니다. 이미 포장되었습니다. 여기서 가장 좋은 방법은 데코레이터, Oldskool 스타일을 수동으로 적용하는 것입니다.
def myfunc1():
pass
myfunc2 = aDecorator(myfunc1)
myfunc3 = bDecorator(myfunc1)
편집 : 또는 조금 더 명확하게하려면
def _tempFunc():
pass
myfunc1 = aDecorator(_tempFunc)
myfunc1()
myfunc1 = bDecorator(_tempFunc)
myfunc1()
여기에 훌륭합니다 당신을 시작하기위한 레시피. 기본적으로 아이디어는 클래스 인스턴스를 데코레이터로 전달하는 것입니다. 그런 다음 클래스 인스턴스에서 속성을 설정하고 (원하는 경우 보그로 만드십시오)이를 사용하여 데코레이터 자체의 동작을 제어 할 수 있습니다.
예는 다음과 같습니다.
class Foo:
def __init__(self, do_apply):
self.do_apply = do_apply
def dec(foo):
def wrap(f):
def func(*args, **kwargs):
if foo.do_apply:
# Do something!
pass
return f(*args, **kwargs)
return func
return wrap
foo = Foo(False)
@dec(foo)
def bar(x):
return x
bar('bar')
foo.do_apply = True
# Decorator now active!
bar('baz')
당연히 "데코레이터 데코레이터"를 통합하여 서명 등을 보존 할 수도 있습니다.
물론 - 기능 객체를 얻고 원하는대로 할 수 있습니다.
# Bypass a decorator
import types
class decorator_test(object):
def __init__(self, f):
self.f = f
def __call__(self):
print "In decorator ... entering: ", self.f.__name__
self.f()
print "In decorator ... exiting: ", self.f.__name__
@decorator_test
def func1():
print "inside func1()"
print "\nCalling func1 with decorator..."
func1()
print "\nBypassing decorator..."
for value in func1.__dict__.values():
if isinstance(value, types.FunctionType) and value.func_name == "func1":
value.__call__()
데코레이터를 설명하고 싶다면 장식 된 기능을 만드는 대신보다 명백한 접근 방식을 선택할 수도 있습니다.
deco1(myfunc1, arg1, arg2)
deco2(myfunc1, arg2, arg3)
deco1 () 및 deco2 ()는 데코레이터가 제공하는 기능을 적용하고 인수와 함께 myfunc1 ()을 호출합니다.
나는 그것이 오래된 스레드라는 것을 알고 있지만 나는 이것을하는 것이 즐거웠다
def change_deco(name, deco, placeholder=' #'):
with open(name + '.py', 'r') as file:
lines = file.readlines()
for idx, string in enumerate(lines):
if placeholder in string and repr(placeholder) not in string:
lines[idx] = f' @{deco}\r\n'
exec(''.join(lines))
return locals()[name]
데코레이터가 함수 인 경우 교체하십시오.
aDecorator = otherDecorator