수업을 어떻게 꾸밀까요?
수업에 적용되는 장식가를 만들려면 어떻게 해야 합니까?
구체적으로, 저는 장식기를 사용하고 싶습니다.addID
구성원을 추가합니다.__id
클래스로, 생성자 변경__init__
시험을 보다id
해당 멤버에 대한 인수입니다.
def getId(self): return self.__id
classdecorator addID(cls):
def __init__(self, id, *args, **kws):
self.__id = id
self.getId = getId
cls.__init__(self, *args, **kws)
@addID
class Foo:
def __init__(self, value1):
self.value1 = value1
위의 내용은 다음과 같아야 합니다.
class Foo:
def __init__(self, id, value1):
self.__id = id
self.value1 = value1
def getId(self): return self.__id
학급의 장식가들이 여러분의 문제에 대한 올바른 해결책인지에 대한 질문과는 별개로:
Python 2.6 이상에서는 @-syntax를 사용하는 클래스 장식자가 있으므로 다음과 같이 쓸 수 있습니다.
@addID
class Foo:
pass
이전 버전에서는 다른 방법으로 수행할 수 있습니다.
class Foo:
pass
Foo = addID(Foo)
그러나 이것은 함수 장식가와 동일하게 작동하며 장식가는 예제에서 수행하고 있는 것이 아닌 새 클래스(또는 수정된 원래 클래스)를 반환해야 합니다.추가ID 데코레이터는 다음과 같습니다.
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__
.
저는 당신이 개요를 설명한 접근 방식 대신 하위 클래스를 고려하기를 원할 수도 있다는 생각에 동의합니다.하지만, 당신의 구체적인 시나리오를 몰라서, 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
생성자를 교체하는 것은 아마도 약간 극적일 수 있지만, 언어는 이러한 종류의 깊은 성찰과 동적 수정을 지원합니다.
아무도 클래스를 동적으로 정의할 수 있다고 설명하지 않았습니다.따라서 하위 클래스를 정의하고 반환하는 데코레이터를 사용할 수 있습니다.
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
Python 2(2.6+에서 이 작업을 계속해야 하는 이유를 설명하는 Blcknight의 코멘트)에서 다음과 같이 사용할 수 있습니다.
class Foo:
pass
FooId = addId(Foo)
그리고 Python 3에서는 다음과 같이 사용합니다(그러나 사용에 주의하십시오).super()
수업 중):
@addId
class Foo:
pass
그래서 당신은 당신의 케이크를 가지고 그것을 먹을 수 있습니다 - 상속과 장식가!
그것은 좋은 관행이 아니며 그것 때문에 그렇게 할 수 있는 메커니즘이 없습니다.당신이 원하는 것을 성취하는 올바른 방법은 상속입니다.
강의 문서를 살펴봅니다.
약간의 예:
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)
이런 식으로 보스는 모든 것을 가지고 있습니다.Employee
자신만의 방법과 회원들도 가지고 있습니다.
저는 상속이 제기된 문제에 더 적합하다는 것에 동의합니다.
저는 이 질문이 수업을 꾸미는 데 정말 유용하다는 것을 알게 되었습니다, 감사합니다.
상속이 Python 2.7, (및 원래 함수의 문서 문자열을 유지 관리하는 @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
, 은시킵니승것식장▁an를▁of다ator,▁▁decor▁which▁the▁raises니킵,승을 올리는 장식자의 매개 변수.AssertionError
.
@decorate_if
는 다만적니다됩용만 됩니다.decorator
한다면condition
으로 됩니다.True
.
그getattr
,callable
및 스트및테@decorate_if
장식기가 부서지지 않도록 사용됩니다.foo()
메서드가 장식 중인 클래스에 없습니다.
여기에는 실제로 학급 장식가가 꽤 잘 구현되어 있습니다.
https://github.com/agiliq/Django-parsley/blob/master/parsley/decorators.py
저는 사실 이것이 꽤 흥미로운 구현이라고 생각합니다.그것이 장식하는 클래스를 하위 분류하기 때문에, 그것은 다음과 같은 것들에서 이 클래스와 똑같이 행동할 것입니다.isinstance
수표
이는 추가적인 이점을 가지고 있습니다.__init__
하여 수정 추된 위 또 양 장 의 식 고 장 문 정 의 자 는 사 용 가self.fields
그래서 변화를 주는 것이 좋습니다.self.fields
결국에는__init__
문제의 클래스에 출마했습니다.
매우 총명하다.
하지만, 당신의 수업에서 당신은 실제로 장식이 시공자를 바꾸기를 원하는데, 저는 이것이 수업 장식가에게 좋은 사용 사례라고 생각하지 않습니다.
다음은 클래스의 매개 변수를 반환하는 문제에 대한 답변 예제입니다.또한 상속 체인을 여전히 존중합니다. 즉, 클래스 자체의 매개 변수만 반환됩니다. 수get_params
는 간단한 예로 추가되었지만 검사 모듈 덕분에 다른 기능을 추가할 수 있습니다.
import inspect
class Parent:
@classmethod
def get_params(my_class):
return list(inspect.signature(my_class).parameters.keys())
class OtherParent:
def __init__(self, a, b, c):
pass
class Child(Parent, OtherParent):
def __init__(self, x, y, z):
pass
print(Child.get_params())
>>['x', 'y', 'z']
에는 장고가 있습니다.method_decorator
모든 장식가를 메소드 장식가로 바꾸는 장식가입니다. 당신은 그것이 어떻게 구현되는지 볼 수 있습니다.django.utils.decorators
:
https://docs.djangoproject.com/en/3.0/topics/class-based-views/intro/ #평가급
언급URL : https://stackoverflow.com/questions/681953/how-to-decorate-a-class
'programing' 카테고리의 다른 글
화면 지우기 - Oracle SQL Developer 바로 가기? (0) | 2023.07.06 |
---|---|
타이프스크립트를 사용하여 특정 길이의 문자열을 선언하려면 어떻게 해야 합니까? (0) | 2023.07.06 |
SQL Server가 데이터 유형 숫자로 변환하는 산술 오버플로 오류를 발생시키는 이유는 무엇입니까? (0) | 2023.07.06 |
Git(숫자 및 크기)의 파일 제한은 무엇입니까? (0) | 2023.07.06 |
Oracle SQL - REGEXP_LIKE에 a-z 또는 A-Z 이외의 문자가 포함되어 있습니다. (0) | 2023.07.06 |