클래스의 Python 장식가
다음과 같은 것을 쓸 수 있습니까?
class Test(object):
def _decorator(self, foo):
foo()
@self._decorator
def bar(self):
pass
실패: self in @self를 알 수 없습니다.
저도 해봤어요.
@Test._decorator(self)
이 또한 실패합니다.테스트 알 수 없음
데코레이터에서 인스턴스 변수를 일시적으로 변경한 후 다시 변경하기 전에 데코레이션된 메서드를 실행하고 싶습니다.
당신이 필요로 하는 것을 이와 같은 것이 해줄 수 있습니까?
class Test(object):
def _decorator(foo):
def magic( self ) :
print "start magic"
foo( self )
print "end magic"
return magic
@_decorator
def bar( self ) :
print "normal call"
test = Test()
test.bar()
이렇게 하면 데코레이터에 액세스하기 위한 자체 호출이 방지되고 일반 메서드로 클래스 네임스페이스에 숨겨집니다.
>>> import stackoverflow
>>> test = stackoverflow.Test()
>>> test.bar()
start magic
normal call
end magic
>>>
질문에 답하기 위해 댓글로 편집:
다른 클래스에서 숨겨진 장식기를 사용하는 방법
class Test(object):
def _decorator(foo):
def magic( self ) :
print "start magic"
foo( self )
print "end magic"
return magic
@_decorator
def bar( self ) :
print "normal call"
_decorator = staticmethod( _decorator )
class TestB( Test ):
@Test._decorator
def bar( self ):
print "override bar in"
super( TestB, self ).bar()
print "override bar out"
print "Normal:"
test = Test()
test.bar()
print
print "Inherited:"
b = TestB()
b.bar()
print
출력:
Normal:
start magic
normal call
end magic
Inherited:
start magic
override bar in
start magic
normal call
end magic
override bar out
end magic
당신이 원하는 것은 가능하지 않습니다.아래 코드가 유효한지 여부를 예로 들어 보겠습니다.
class Test(object):
def _decorator(self, foo):
foo()
def bar(self):
pass
bar = self._decorator(bar)
물론, 그것은 유효하지 않습니다.self
그 시점에서 정의되지 않았습니다.마지로가도 입니다.Test
클래스 자체가 정의되기 전까지는 정의되지 않기 때문입니다.제가 이 코드 조각을 보여드리는 이유는 장식가 조각이 변형되기 때문입니다.
따라서 장식가는 인스턴스화 중이 아니라 연결된 기능/메소드를 정의하는 동안 적용되기 때문에 이러한 장식가의 인스턴스에 액세스하는 것은 실제로 불가능합니다.
클래스 수준 액세스가 필요한 경우 다음을 시도하십시오.
class Test(object):
@classmethod
def _decorator(cls, foo):
foo()
def bar(self):
pass
Test.bar = Test._decorator(Test.bar)
import functools
class Example:
def wrapper(func):
@functools.wraps(func)
def wrap(self, *args, **kwargs):
print("inside wrap")
return func(self, *args, **kwargs)
return wrap
@wrapper
def method(self):
print("METHOD")
wrapper = staticmethod(wrapper)
e = Example()
e.method()
이 방법을 사용하여 액세스할 수 있습니다.self
에의 에서.decorator
동일한 클래스 내에서 정의됨:
class Thing(object):
def __init__(self, name):
self.name = name
def debug_name(function):
def debug_wrapper(*args):
self = args[0]
print 'self.name = ' + self.name
print 'running function {}()'.format(function.__name__)
function(*args)
print 'self.name = ' + self.name
return debug_wrapper
@debug_name
def set_name(self, new_name):
self.name = new_name
출테력(트대상스테대))에서 테스트됨)Python 2.7.10
):
>>> a = Thing('A')
>>> a.name
'A'
>>> a.set_name('B')
self.name = A
running function set_name()
self.name = B
>>> a.name
'B'
위의 예는 어리석지만 효과가 있습니다.
다음은 몇 단계 더 나아가기 위한 Michael Speer의 답변에 대한 확장입니다.
인수를 사용하고 인수와 반환 값을 사용하여 함수에 대해 작업하는 인스턴스 메서드 장식자입니다.
class Test(object):
"Prints if x == y. Throws an error otherwise."
def __init__(self, x):
self.x = x
def _outer_decorator(y):
def _decorator(foo):
def magic(self, *args, **kwargs) :
print("start magic")
if self.x == y:
return foo(self, *args, **kwargs)
else:
raise ValueError("x ({}) != y ({})".format(self.x, y))
print("end magic")
return magic
return _decorator
@_outer_decorator(y=3)
def bar(self, *args, **kwargs) :
print("normal call")
print("args: {}".format(args))
print("kwargs: {}".format(kwargs))
return 27
그리고 나서.
In [2]:
test = Test(3)
test.bar(
13,
'Test',
q=9,
lollipop=[1,2,3]
)
start magic
normal call
args: (13, 'Test')
kwargs: {'q': 9, 'lollipop': [1, 2, 3]}
Out[2]:
27
In [3]:
test = Test(4)
test.bar(
13,
'Test',
q=9,
lollipop=[1,2,3]
)
start magic
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-3-576146b3d37e> in <module>()
4 'Test',
5 q=9,
----> 6 lollipop=[1,2,3]
7 )
<ipython-input-1-428f22ac6c9b> in magic(self, *args, **kwargs)
11 return foo(self, *args, **kwargs)
12 else:
---> 13 raise ValueError("x ({}) != y ({})".format(self.x, y))
14 print("end magic")
15 return magic
ValueError: x (4) != y (3)
저는 매우 유사한 문제를 조사하던 중 이 질문을 발견했습니다.제 해결책은 문제를 두 부분으로 나누는 것입니다.먼저 클래스 메소드와 연결할 데이터를 캡처해야 합니다.이 경우 handler_for는 유닉스 명령을 해당 명령의 출력에 대한 처리기와 연결합니다.
class OutputAnalysis(object):
"analyze the output of diagnostic commands"
def handler_for(name):
"decorator to associate a function with a command"
def wrapper(func):
func.handler_for = name
return func
return wrapper
# associate mount_p with 'mount_-p.txt'
@handler_for('mount -p')
def mount_p(self, slurped):
pass
이제 각 클래스 메소드에 일부 데이터를 연결했으므로 해당 데이터를 수집하여 클래스 속성에 저장해야 합니다.
OutputAnalysis.cmd_handler = {}
for value in OutputAnalysis.__dict__.itervalues():
try:
OutputAnalysis.cmd_handler[value.handler_for] = value
except AttributeError:
pass
일부 디버깅 상황에서 이러한 유형의 데코레이터를 사용하면 호출 함수를 찾을 필요 없이 데코레이션을 통해 클래스 속성을 재정의할 수 있습니다.
class myclass(object):
def __init__(self):
self.property = "HELLO"
@adecorator(property="GOODBYE")
def method(self):
print self.property
여기 데코레이터 코드가 있습니다.
class adecorator (object):
def __init__ (self, *args, **kwargs):
# store arguments passed to the decorator
self.args = args
self.kwargs = kwargs
def __call__(self, func):
def newf(*args, **kwargs):
#the 'self' for a method function is passed as args[0]
slf = args[0]
# replace and store the attributes
saved = {}
for k,v in self.kwargs.items():
if hasattr(slf, k):
saved[k] = getattr(slf,k)
setattr(slf, k, v)
# call the method
ret = func(*args, **kwargs)
#put things back
for k,v in saved.items():
setattr(slf, k, v)
return ret
newf.__doc__ = func.__doc__
return newf
참고: 클래스 장식자를 사용했기 때문에 장식자 클래스 생성자에게 인수를 전달하지 않더라도 기능을 장식하려면 괄호가 있는 @adecorator()를 사용해야 합니다.
간단한 방법입니다.당신이 필요한 것은 데코레이터 방법을 수업 밖에 두는 것입니다.안에서 계속 사용할 수 있습니다.
def my_decorator(func):
#this is the key line. There's the aditional self parameter
def wrap(self, *args, **kwargs):
# you can use self here as if you were inside the class
return func(self, *args, **kwargs)
return wrap
class Test(object):
@my_decorator
def bar(self):
pass
내부 클래스에서 선언합니다.이 솔루션은 매우 견고하며 권장됩니다.
class Test(object):
class Decorators(object):
@staticmethod
def decorator(foo):
def magic(self, *args, **kwargs) :
print("start magic")
foo(self, *args, **kwargs)
print("end magic")
return magic
@Decorators.decorator
def bar( self ) :
print("normal call")
test = Test()
test.bar()
결과:
>>> test = Test()
>>> test.bar()
start magic
normal call
end magic
>>>
장식가는 일반적으로 인스턴스 속성에 의존하는 객체 메소드의 기능성에 비해 전체 객체(함수 객체 포함)의 기능성을 수정하는 데 더 적합한 것으로 보입니다.예:
def mod_bar(cls):
# returns modified class
def decorate(fcn):
# returns decorated function
def new_fcn(self):
print self.start_str
print fcn(self)
print self.end_str
return new_fcn
cls.bar = decorate(cls.bar)
return cls
@mod_bar
class Test(object):
def __init__(self):
self.start_str = "starting dec"
self.end_str = "ending dec"
def bar(self):
return "bar"
출력은 다음과 같습니다.
>>> import Test
>>> a = Test()
>>> a.bar()
starting dec
bar
ending dec
도움이 될 만한 데코레이터 구현이 있습니다.
import functools
import datetime
class Decorator(object):
def __init__(self):
pass
def execution_time(func):
@functools.wraps(func)
def wrap(self, *args, **kwargs):
""" Wrapper Function """
start = datetime.datetime.now()
Tem = func(self, *args, **kwargs)
end = datetime.datetime.now()
print("Exection Time:{}".format(end-start))
return Tem
return wrap
class Test(Decorator):
def __init__(self):
self._MethodName = Test.funca.__name__
@Decorator.execution_time
def funca(self):
print("Running Function : {}".format(self._MethodName))
return True
if __name__ == "__main__":
obj = Test()
data = obj.funca()
print(data)
장식자를 장식할 수 있습니다.
import decorator
class Test(object):
@decorator.decorator
def _decorator(foo, self):
foo(self)
@_decorator
def bar(self):
pass
정적 방법을 사용하고 장식기의 내부 기능(랩퍼)에 추가 모수(자체)를 포함합니다.
import functools
class Test:
@staticmethod
def _decorator(f):
@functools.wraps(f)
def _wrapper(self, *args, **kwargs):
# do some serious decorating (incl. calls to self!)
print(self)
return f(self, *args, **kwargs)
return _wrapper
@_decorator
def bar(self):
return 42
언급URL : https://stackoverflow.com/questions/1263451/python-decorators-in-classes
'programing' 카테고리의 다른 글
ASP.NEC#에 각각 대해 CheckBoxList에서 선택한 항목의 값을 가져오는 방법은 무엇입니까? (0) | 2023.06.10 |
---|---|
vba는 셀 그룹을 기능 범위로 전달합니다. (0) | 2023.06.10 |
소스 파일에도 'external C'를 추가해야 합니까? (0) | 2023.06.10 |
Oracle의 SEQUENCE.NEXTVAL에 해당하는 MySQL (0) | 2023.06.10 |
속성 'id'가 'T' 유형에 없습니다. (2339) 유형 스크립트 Generics 스크립트 Generics 오류 (0) | 2023.06.10 |