programing

수업을 어떻게 꾸밀까요?

instargram 2023. 7. 6. 21:48
반응형

수업을 어떻게 꾸밀까요?

수업에 적용되는 장식가를 만들려면 어떻게 해야 합니까?

구체적으로, 저는 장식기를 사용하고 싶습니다.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://github.com/django/django/blob/50cf183d219face91822c75fa0a15fe2fe3cb32d/django/utils/decorators.py#L53

https://docs.djangoproject.com/en/3.0/topics/class-based-views/intro/ #평가급

언급URL : https://stackoverflow.com/questions/681953/how-to-decorate-a-class

반응형