문제

기능이있는 경우 :


@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
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top