문제

예를 들어 Java에서 @Override 주석은 재정의 시간을 컴파일 타임 점검 할뿐만 아니라 우수한 자체 문서화 코드를 만듭니다.

나는 단지 문서를 찾고 있습니다 (Pylint와 같은 일부 체커의 지표라면 보너스입니다). 어딘가에 댓글이나 문서화를 추가 할 수 있지만 파이썬의 재정의를 나타내는 관용적 방법은 무엇입니까?

도움이 되었습니까?

해결책

Update (23.05.2015) : 이것과 fwc : s 답변을 기반으로 PIP 설치 가능 패키지를 만들었습니다. https://github.com/mkorpela/overrides

때때로 나는이 질문을보고 있습니다. 주로 이것은 코드베이스에서 동일한 버그를보고 (다시) 발생합니다. 누군가 "인터페이스"에서 메소드를 바꾸는 동안 누군가 "인터페이스"구현 클래스를 잊어 버렸습니다. ..

Python은 Java가 아니지만 Python은 힘을 가지고 있으며 명시 적은 암시적인 것보다 낫습니다. 실제 세계에는이 일이 나를 도울 수있는 실제 구체적인 사례가 있습니다.

따라서 여기에 재정의 데코레이터의 스케치가 있습니다. 이것은 매개 변수로 주어진 클래스가 장식중인 메소드와 동일한 메소드 (또는 무언가) 이름을 가지고 있는지 확인합니다.

더 나은 솔루션을 생각할 수 있다면 여기에 게시하십시오!

def overrides(interface_class):
    def overrider(method):
        assert(method.__name__ in dir(interface_class))
        return method
    return overrider

다음과 같이 작동합니다.

class MySuperInterface(object):
    def my_method(self):
        print 'hello world!'


class ConcreteImplementer(MySuperInterface):
    @overrides(MySuperInterface)
    def my_method(self):
        print 'hello kitty!'

결함이있는 버전을 수행하면 클래스 로딩 중에 어설 션 오류가 발생합니다.

class ConcreteFaultyImplementer(MySuperInterface):
    @overrides(MySuperInterface)
    def your_method(self):
        print 'bye bye!'

>> AssertionError!!!!!!!

다른 팁

다음은 Interface_Class 이름의 사양이 필요하지 않은 구현입니다.

import inspect
import re

def overrides(method):
    # actually can't do this because a method is really just a function while inside a class def'n  
    #assert(inspect.ismethod(method))

    stack = inspect.stack()
    base_classes = re.search(r'class.+\((.+)\)\s*\:', stack[2][4][0]).group(1)

    # handle multiple inheritance
    base_classes = [s.strip() for s in base_classes.split(',')]
    if not base_classes:
        raise ValueError('overrides decorator: unable to determine base class') 

    # stack[0]=overrides, stack[1]=inside class def'n, stack[2]=outside class def'n
    derived_class_locals = stack[2][0].f_locals

    # replace each class name in base_classes with the actual class type
    for i, base_class in enumerate(base_classes):

        if '.' not in base_class:
            base_classes[i] = derived_class_locals[base_class]

        else:
            components = base_class.split('.')

            # obj is either a module or a class
            obj = derived_class_locals[components[0]]

            for c in components[1:]:
                assert(inspect.ismodule(obj) or inspect.isclass(obj))
                obj = getattr(obj, c)

            base_classes[i] = obj


    assert( any( hasattr(cls, method.__name__) for cls in base_classes ) )
    return method

문서화 목적으로 만 원한다면 자신의 재정의 데코레이터를 정의 할 수 있습니다.

def override(f):
    return f


class MyClass (BaseClass):

    @override
    def method(self):
        pass

실제로 재정의를 확인하는 방식으로 재정의 (f)를 만들지 않는 한 이것은 실제로 눈을 사로 잡는 것입니다.

그러나 이것은 파이썬입니다. 왜 Java처럼 쓰는가?

파이썬은 Java가 아닙니다. 물론 컴파일 타임 점검과 같은 것은 없습니다.

Docstring의 의견이 충분하다고 생각합니다. 이를 통해 메소드 사용자가 입력 할 수 있습니다 help(obj.method) 그리고이 방법이 재정의임을 확인하십시오.

인터페이스를 명시 적으로 확장 할 수도 있습니다 class Foo(Interface), 이를 통해 사용자가 입력 할 수 있습니다 help(Interface.method) 기능에 대한 아이디어를 얻으려면 방법이 제공해야합니다.

다른 사람들이 Java와 달리 @overide 태그는 없지만 위의 데코레이터를 사용하여 자신의 직접 만들 수는 있지만 내부 DICT를 사용하는 대신 getAttrib () 글로벌 메소드를 사용하여 다음과 같은 것을 얻는 것이 좋습니다.

def Override(superClass):
    def method(func)
        getattr(superClass,method.__name__)
    return method

당신이 원한다면 당신이 자신의 시도 캐치에서 getAttr ()를 잡을 수 있지만이 경우 getAttr 방법이 더 좋다고 생각합니다.

또한 클래스 방법과 vairables를 포함하여 클래스에 바인딩 된 모든 항목을 포착합니다.

@mkorpela의 즉흥 훌륭한 대답, 여기에 버전이 있습니다

보다 정확한 수표, 이름 지정 및 오류 오브젝트가 높아짐

def overrides(interface_class):
    """
    Function override annotation.
    Corollary to @abc.abstractmethod where the override is not of an
    abstractmethod.
    Modified from answer https://stackoverflow.com/a/8313042/471376
    """
    def confirm_override(method):
        if method.__name__ not in dir(interface_class):
            raise NotImplementedError('function "%s" is an @override but that'
                                      ' function is not implemented in base'
                                      ' class %s'
                                      % (method.__name__,
                                         interface_class)
                                      )

        def func():
            pass

        attr = getattr(interface_class, method.__name__)
        if type(attr) is not type(func):
            raise NotImplementedError('function "%s" is an @override'
                                      ' but that is implemented as type %s'
                                      ' in base class %s, expected implemented'
                                      ' type %s'
                                      % (method.__name__,
                                         type(attr),
                                         interface_class,
                                         type(func))
                                      )
        return method
    return confirm_override


실제로는 다음과 같습니다.

NotImplementedError "기본 클래스에서 구현되지 않았습니다"

class A(object):
    # ERROR: `a` is not a implemented!
    pass

class B(A):
    @overrides(A)
    def a(self):
        pass

더 설명적인 결과 NotImplementedError 오류

function "a" is an @override but that function is not implemented in base class <class '__main__.A'>

전체 스택

Traceback (most recent call last):
  …
  File "C:/Users/user1/project.py", line 135, in <module>
    class B(A):
  File "C:/Users/user1/project.py", line 136, in B
    @overrides(A)
  File "C:/Users/user1/project.py", line 110, in confirm_override
    interface_class)
NotImplementedError: function "a" is an @override but that function is not implemented in base class <class '__main__.A'>


NotImplementedError "예상 구현 유형"

class A(object):
    # ERROR: `a` is not a function!
    a = ''

class B(A):
    @overrides(A)
    def a(self):
        pass

더 설명적인 결과 NotImplementedError 오류

function "a" is an @override but that is implemented as type <class 'str'> in base class <class '__main__.A'>, expected implemented type <class 'function'>

전체 스택

Traceback (most recent call last):
  …
  File "C:/Users/user1/project.py", line 135, in <module>
    class B(A):
  File "C:/Users/user1/project.py", line 136, in B
    @overrides(A)
  File "C:/Users/user1/project.py", line 125, in confirm_override
    type(func))
NotImplementedError: function "a" is an @override but that is implemented as type <class 'str'> in base class <class '__main__.A'>, expected implemented type <class 'function'>




@mkorpela 답변의 가장 큰 장점은 일부 초기화 단계에서 확인이 발생한다는 것입니다. 수표는 "실행"될 필요가 없습니다. 이전 예제를 참조하고 class B 초기화되지 않습니다 (B()) 아직 NotImplementedError 여전히 올릴 것입니다. 이것은 의미합니다 overrides 오류는 더 빨리 잡혔습니다.

@mkorpela의 위대한 답변을 기반으로 비슷한 패키지를 썼습니다.iPromise pypi github) 더 많은 점검을 수행합니다.

B와 C의 상속을 가정하고 B는 C. ipromise에서 상속한다고 가정합니다.

  • AF가 BF를 재정의하는 경우 BF가 존재해야하며 B에서 물려받을 수 있습니다.

  • AF 패턴은 BF를 무시한다고 선언하지 않으며, 이는 B 가이 방법을 재정의하지 않기로 결정할 수 있으므로 CF에서 CF를 무시한다고 말해야한다고 선언합니다. 따라서 다운 스트림 업데이트가 발생하지 않아야합니다.

  • AF 패턴은 CF를 무시한다고 선언하지 않지만 BF는 재정의를 선언하지 않습니다.

  • AF 패턴은 CF를 무시한다고 선언하지 않지만 BF는 일부 DF에서 재정의한다고 선언합니다.

또한 추상 방법을 구현하고 확인하는 다양한 기능이 있습니다.

듣기는 Jython에서 Java 수업과 함께 가장 간단하고 일합니다.

class MyClass(SomeJavaClass):
     def __init__(self):
         setattr(self, "name_of_method_to_override", __method_override__)

     def __method_override__(self, some_args):
         some_thing_to_do()
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top