[PYTHON] 파이썬 클래스 장식 자
PYTHON파이썬 클래스 장식 자
파이썬 2.5에서는 클래스를 꾸미는 데코레이터를 만드는 방법이 있습니까? 특히, 데코레이터를 사용하여 클래스에 멤버를 추가하고 생성자를 변경하여 해당 멤버의 값을 가져 오려고합니다.
다음과 같은 것을 찾으십시오 ( 'class Foo :'에 구문 오류가 있습니다 :
def getId(self): return self.__id
class addID(original_class):
def __init__(self, id, *args, **kws):
self.__id = id
self.getId = getId
original_class.__init__(self, *args, **kws)
@addID
class Foo:
def __init__(self, value1):
self.value1 = value1
if __name__ == '__main__':
foo1 = Foo(5,1)
print foo1.value1, foo1.getId()
foo2 = Foo(15,2)
print foo2.value1, foo2.getId()
내가 겪은 일은 파이썬에서 C # 인터페이스와 같은 일을하는 방법이다. 내가 생각하는 패러다임을 전환해야합니다.
해결법
-
==============================
1.앞서 설명한 접근 방식 대신 하위 클래스를 고려할 수도 있다는 개념이 두 번째입니다. 그러나 특정 시나리오를 모르는 경우 YMMV :-)
앞서 설명한 접근 방식 대신 하위 클래스를 고려할 수도 있다는 개념이 두 번째입니다. 그러나 특정 시나리오를 모르는 경우 YMMV :-)
당신이 생각하는 것은 메타 클래스입니다. 메타 클래스의 __new__ 함수는 클래스의 제안 된 전체 정의에 전달되며 클래스 정의가 작성되기 전에 다시 작성할 수 있습니다. 그 때 생성자를 새 것으로 만들 수 있습니다.
예:
def substitute_init(self, id, *args, **kwargs): pass class FooMeta(type): def __new__(cls, name, bases, attrs): attrs['__init__'] = substitute_init return super(FooMeta, cls).__new__(cls, name, bases, attrs) class Foo(object): __metaclass__ = FooMeta def __init__(self, value1): pass
생성자를 교체하는 것은 다소 극적 일 수 있지만이 언어는 이러한 종류의 심층적 인 내성 및 동적 수정을 지원합니다.
-
==============================
2.클래스 데코레이터가 문제에 대한 올바른 해결책인지 여부는 별개입니다.
클래스 데코레이터가 문제에 대한 올바른 해결책인지 여부는 별개입니다.
Python 2.6 이상에서는 @ -yntax가있는 클래스 데코레이터가 있으므로 다음과 같이 작성할 수 있습니다.
@addID class Foo: pass
이전 버전에서는 다음과 같이 할 수 있습니다.
class Foo: pass Foo = addID(Foo)
그러나 이것은 함수 데코레이터에서와 똑같이 작동하며 데코레이터는 예제에서 수행하지 않은 새로운 (또는 수정 된 원본) 클래스를 리턴해야한다는 점에 유의하십시오. addID 데코레이터는 다음과 같습니다.
def addID(original_class): orig_init = original_class.__init__ # Make copy of original __init__, so we can call it without recursion def __init__(self, id, *args, **kws): self.__id = id self.getId = getId orig_init(self, *args, **kws) # Call the original __init__ original_class.__init__ = __init__ # Set the class' __init__ to the new one return original_class
그런 다음 위에서 설명한대로 Python 버전에 적절한 구문을 사용할 수 있습니다.
하지만 당신이 __init__를 오버라이드하고 싶다면 상속이 더 적합하다고 다른 사람들과 동의합니다.
-
==============================
3.그건 좋은 습관이 아니기 때문에 그렇게하는 메커니즘이 없습니다. 당신이 원하는 것을 성취하는 올바른 방법은 상속입니다.
그건 좋은 습관이 아니기 때문에 그렇게하는 메커니즘이 없습니다. 당신이 원하는 것을 성취하는 올바른 방법은 상속입니다.
수업 자료를 살펴보십시오.
작은 예 :
class Employee(object): def __init__(self, age, sex, siblings=0): self.age = age self.sex = sex self.siblings = siblings def born_on(self): today = datetime.date.today() return today - datetime.timedelta(days=self.age*365) class Boss(Employee): def __init__(self, age, sex, siblings=0, bonus=0): self.bonus = bonus Employee.__init__(self, age, sex, siblings)
이 방법으로 Boss는 Employee가 가지고있는 모든 것을 가지고 있으며, 또한 자신의 __init__ 메소드와 멤버를 보유하고 있습니다.
-
==============================
4.클래스를 동적으로 정의 할 수 있다고 설명하는 사람은 없습니다. 따라서 하위 클래스를 정의하고 리턴하는 데코레이터를 가질 수 있습니다.
클래스를 동적으로 정의 할 수 있다고 설명하는 사람은 없습니다. 따라서 하위 클래스를 정의하고 리턴하는 데코레이터를 가질 수 있습니다.
def addId(cls): class AddId(cls): def __init__(self, id, *args, **kargs): super(AddId, self).__init__(*args, **kargs) self.__id = id def getId(self): return self.__id return AddId
어떤 것을 파이썬 2에서 사용할 수 있는가? (Blckknght의 코멘트, 2.6+에서 이것을 계속해야하는 이유를 설명한다) :
class Foo: pass FooId = addId(Foo)
그리고 파이썬 3에서는 이렇게합니다 (그러나 클래스에서 super ()를 사용하도록주의하십시오).
@addId class Foo: pass
그래서 여러분은 여러분의 케이크를 가지고 그것을 먹을 수 있습니다 - 상속과 장식 자들!
-
==============================
5.실제로 클래스 데코레이터의 구현은 매우 훌륭합니다.
실제로 클래스 데코레이터의 구현은 매우 훌륭합니다.
https://github.com/agiliq/Django-parsley/blob/master/parsley/decorators.py
실제로 이것이 꽤 흥미로운 구현이라고 생각합니다. 클래스가 꾸미는 클래스를 서브 클래스하기 때문에 isinstance 체크와 같은 클래스에서와 똑같이 동작합니다.
추가 장점이 있습니다 : 커스텀 장고 양식의 __init__ 문이 self.fields를 수정하거나 추가하는 것은 드문 일이 아니므로, 문제의 클래스에 대해 __init__가 모두 실행 된 후에 self.fields에 대한 변경이 발생하는 것이 더 좋습니다.
매우 영리한.
그러나 클래스에서 실제로 데코레이션이 생성자를 변경하기를 원합니다. 클래스 데코레이터의 좋은 사용 사례는 아닌 것 같습니다.
-
==============================
6.나는 상속이 문제 제기에 더 잘 어울리는 것에 동의한다.
나는 상속이 문제 제기에 더 잘 어울리는 것에 동의한다.
이 질문은 클래스 꾸미기에 정말 편리하다고 생각합니다. 모두 감사합니다.
상속이 Python 2.7에서 영향을 미치는 방법 (원래 함수의 docstring을 유지하는 @wraps 등)을 비롯한 몇 가지 예제가 있습니다.
def dec(klass): old_foo = klass.foo @wraps(klass.foo) def decorated_foo(self, *args ,**kwargs): print('@decorator pre %s' % msg) old_foo(self, *args, **kwargs) print('@decorator post %s' % msg) klass.foo = decorated_foo return klass @dec # No parentheses class Foo...
데코레이터에 매개 변수를 추가하려는 경우가 종종 있습니다.
from functools import wraps def dec(msg='default'): def decorator(klass): old_foo = klass.foo @wraps(klass.foo) def decorated_foo(self, *args ,**kwargs): print('@decorator pre %s' % msg) old_foo(self, *args, **kwargs) print('@decorator post %s' % msg) klass.foo = decorated_foo return klass return decorator @dec('foo decorator') # You must add parentheses now, even if they're empty class Foo(object): def foo(self, *args, **kwargs): print('foo.foo()') @dec('subfoo decorator') class SubFoo(Foo): def foo(self, *args, **kwargs): print('subfoo.foo() pre') super(SubFoo, self).foo(*args, **kwargs) print('subfoo.foo() post') @dec('subsubfoo decorator') class SubSubFoo(SubFoo): def foo(self, *args, **kwargs): print('subsubfoo.foo() pre') super(SubSubFoo, self).foo(*args, **kwargs) print('subsubfoo.foo() post') SubSubFoo().foo()
출력 :
@decorator pre subsubfoo decorator subsubfoo.foo() pre @decorator pre subfoo decorator subfoo.foo() pre @decorator pre foo decorator foo.foo() @decorator post foo decorator subfoo.foo() post @decorator post subfoo decorator subsubfoo.foo() post @decorator post subsubfoo decorator
함수 장식자를 좀 더 간결하게 사용 했으므로 함수 장식자를 사용했습니다. 다음은 클래스를 꾸미는 클래스입니다.
class Dec(object): def __init__(self, msg): self.msg = msg def __call__(self, klass): old_foo = klass.foo msg = self.msg def decorated_foo(self, *args, **kwargs): print('@decorator pre %s' % msg) old_foo(self, *args, **kwargs) print('@decorator post %s' % msg) klass.foo = decorated_foo return klass
이러한 괄호를 검사하고 데코 레이팅 된 클래스에 메서드가없는 경우 작동하는보다 강력한 버전입니다.
from inspect import isclass def decorate_if(condition, decorator): return decorator if condition else lambda x: x def dec(msg): # Only use if your decorator's first parameter is never a class assert not isclass(msg) def decorator(klass): old_foo = getattr(klass, 'foo', None) @decorate_if(old_foo, wraps(klass.foo)) def decorated_foo(self, *args ,**kwargs): print('@decorator pre %s' % msg) if callable(old_foo): old_foo(self, *args, **kwargs) print('@decorator post %s' % msg) klass.foo = decorated_foo return klass return decorator
Assert는 데코레이터가 괄호없이 사용되지 않았는지 확인합니다. 있다면, 데코 레이팅되는 클래스는 데코레이터의 msg 매개 변수에 전달되어 AssertionError를 발생시킵니다.
@decorate_if는 조건이 True로 평가되는 경우에만 데코레이터를 적용합니다.
getattr, callable test 및 @decorate_if는 데코레이터가 장식 될 클래스에 foo () 메서드가 없으면 데코레이터가 중단되지 않도록하기 위해 사용됩니다.
from https://stackoverflow.com/questions/681953/python-class-decorator by cc-by-sa and MIT license
'PYTHON' 카테고리의 다른 글
[PYTHON] json.dumps 대 flask.jsonify (0) | 2018.10.06 |
---|---|
[PYTHON] Python : 사전을 사용하여 목록의 항목 계산 [duplicate] (0) | 2018.10.06 |
[PYTHON] 어떻게 파이썬에서 트리를 구현할 수 있습니까? Java와 같이 파이썬에 내장 된 데이터 구조가 있습니까? (0) | 2018.10.06 |
[PYTHON] 어떻게 장고 DateTimeField의 날짜를 필터링 할 수 있습니까? (0) | 2018.10.06 |
[PYTHON] 파이썬에서 전체 파일 읽기 (0) | 2018.10.06 |