한 메소드의 독스트링을 사용하여 다른 메소드의 독스트링을 자동으로 덮어쓰기

StackOverflow https://stackoverflow.com/questions/71817

  •  09-06-2019
  •  | 
  •  

문제

문제:템플릿 메서드가 포함된 클래스가 있습니다. execute 다른 메소드를 호출하는 것 _execute.하위 클래스는 덮어쓰기로 되어 있습니다. _execute 특정 기능을 구현합니다.이 기능은 다음 문서화 문자열에 문서화되어야 합니다. _execute.고급 사용자는 자신만의 하위 클래스를 만들어 라이브러리를 확장할 수 있습니다.그러나 그러한 하위 클래스를 다루는 다른 사용자는 다음을 사용해야 합니다. execute, 따라서 그가 사용하는 경우 올바른 독스트링을 볼 수 없습니다. help(execute).

그러므로 하위 클래스에서 다음의 독스트링을 사용하는 방식으로 기본 클래스를 수정하는 것이 좋을 것입니다. execute 자동으로 다음 항목으로 대체됩니다. _execute.이 작업을 어떻게 수행할 수 있는지 아이디어가 있습니까?

나는 이를 사용자에게 완전히 투명하게 만들기 위해 메타클래스를 생각하고 있었습니다.

도움이 되었습니까?

해결책

음, 하위 클래스에서 원래 메서드를 복사해도 괜찮다면 다음 기술을 사용할 수 있습니다.

import new

def copyfunc(func):
    return new.function(func.func_code, func.func_globals, func.func_name,
                        func.func_defaults, func.func_closure)

class Metaclass(type):
    def __new__(meta, name, bases, attrs):
        for key in attrs.keys():
            if key[0] == '_':
                skey = key[1:]
                for base in bases:
                    original = getattr(base, skey, None)
                    if original is not None:
                        copy = copyfunc(original)
                        copy.__doc__ = attrs[key].__doc__
                        attrs[skey] = copy
                        break
        return type.__new__(meta, name, bases, attrs)

class Class(object):
    __metaclass__ = Metaclass
    def execute(self):
        '''original doc-string'''
        return self._execute()

class Subclass(Class):
    def _execute(self):
        '''sub-class doc-string'''
        pass

다른 팁

기본 클래스를 재정의할 수 없는 이유가 있나요? execute 직접 기능?

class Base(object):
    def execute(self):
        ...

class Derived(Base):
    def execute(self):
        """Docstring for derived class"""
        Base.execute(self)
        ...stuff specific to Derived...

위의 작업을 수행하고 싶지 않은 경우:

메소드 객체는 쓰기를 지원하지 않습니다. __doc__ 속성이므로 변경해야 합니다. __doc__ 실제 함수 객체에서.기본 클래스의 클래스를 재정의하고 싶지 않기 때문에 각 하위 클래스에 자체 복사본을 제공해야 합니다. execute:

class Derived(Base):
    def execute(self):
        return Base.execute(self)

    class _execute(self):
        """Docstring for subclass"""
        ...

    execute.__doc__= _execute.__doc__

하지만 이는 재정의하는 우회적인 방법과 유사합니다. execute...

functools.wraps() 데코레이터를 살펴보세요.이 모든 작업을 수행하지만 올바른 컨텍스트에서 실행할 수 있는지 직접 알 수 없습니다.

문서 문자열은 다음 위치에 저장됩니다. __doc__ 따라서 문서 문자열을 기반으로 다시 할당하는 것이 그리 어렵지 않을 것입니다. _execute 사실 이후.

원래:

class MyClass(object):
    def execute(self):
        '''original doc-string'''
        self._execute()

class SubClass(MyClass):
    def _execute(self):
        '''sub-class doc-string'''
        pass

    # re-assign doc-string of execute
    def execute(self,*args,**kw):
        return MyClass.execute(*args,**kw)
    execute.__doc__=_execute.__doc__

문서 문자열이 실행 버전에 연결되도록 실행을 다시 선언해야 합니다. SubClass 그리고를 위해서가 아니라 MyClass (그렇지 않으면 다른 하위 클래스를 방해하게 됩니다)

이는 매우 깔끔한 방법은 아니지만 라이브러리 사용자의 POV에서는 원하는 결과를 제공해야 합니다.그런 다음 이를 하위 클래스로 분류하는 사람들이 더 쉽게 만들 수 있도록 메타 클래스로 마무리할 수 있습니다.

나는 이것에 접근하는 가장 간단하고 가장 Python적인 방법이 단순히 하위 클래스에서 실행을 재정의하고 기본 클래스의 실행 메서드를 호출하도록 하는 것이라는 데 동의합니다.

class Sub(Base):
    def execute(self):
        """New docstring goes here"""
        return Base.execute(self)

이것은 원하는 것을 달성하기 위한 아주 작은 코드입니다.유일한 단점은 Base를 확장하는 모든 하위 클래스에서 이 코드를 반복해야 한다는 것입니다.그러나 이는 원하는 행동에 대해 지불하기에는 작은 대가입니다.

실행을 위한 독스트링이 동적으로 생성되는지 확인하는 엉성하고 장황한 방법을 원한다면 여기에 있는 다른 제안보다 코드가 훨씬 적은 설명자 프로토콜을 사용할 수 있습니다.이는 기존 함수에 설명자를 설정할 수 없기 때문에 짜증나는 일입니다. 즉, 실행은 다음과 같은 별도의 클래스로 작성되어야 합니다. __call__ 방법.

이 작업을 수행하는 코드는 다음과 같습니다. 하지만 위의 예는 훨씬 더 간단하고 Python에 가깝습니다.

class Executor(object):
    __doc__ = property(lambda self: self.inst._execute.__doc__)

    def __call__(self):
        return self.inst._execute()

class Base(object):
    execute = Executor()

class Sub(Base):
    def __init__(self):
        self.execute.inst = self

    def _execute(self):
        """Actually does something!"""
        return "Hello World!"

spam = Sub()
print spam.execute.__doc__  # prints "Actually does something!"
help(spam)                  # the execute method says "Actually does something!"
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top