Python에서는 메서드를 덮어쓰고 있다는 것을 어떻게 표시합니까?
에서는 " " " " 입니다.@Override
주석은 오버라이드의 컴파일 시간 체크를 제공할 뿐만 아니라 뛰어난 자기 인식 코드를 제공합니다.
문서를 찾고 있습니다(단, pylint와 같은 체커에 대한 지표라면 보너스입니다).코멘트나 docstring을 추가할 수 있는데 Python에서 오버라이드를 나타내는 관용적인 방법은 무엇입니까?
이것과 fwc:s의 답변을 바탕으로 pip 설치 가능 패키지를 만들었습니다.https://github.com/mkorpela/overrides
나는 가끔 이 질문을 보게 된다.이것은 주로 코드 베이스에서 같은 버그가 검출된 후에 발생합니다.누군가가 "interface"에서 메서드의 이름을 변경하는 동안 일부 "interface" 구현 클래스를 잊어버렸습니다.
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
실제로 오버라이드를 체크하는 방법으로 오버라이드를 작성하지 않는 한 이는 눈에 보이는 캔디일 뿐입니다.
근데 이게 Python인데 왜 자바처럼 쓰는 거야?
@mkorpela great answer를 즉흥적으로 표현하면 다음과 같은 버전이 있습니다.
보다 정밀한 검사, 이름 지정 및 상승된 오류 발생 오류 개체
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
이치노
파이썬은 자바가 아니야물론 컴파일 타임 체크 같은 것은 없습니다.
나는 문서 문자열의 코멘트는 충분하다고 생각한다.가 입력이 합니다.help(obj.method)
이치노
, 를 확장할 도 있습니다.class Foo(Interface)
는 "이러다"를 입력할 수 help(Interface.method)
사용방법이 제공하는 기능에 대한 아이디어를 얻을 수 있습니다.
Java와는 달리 @Overide 태그는 없지만 위의 경우 데코레이터를 사용하여 직접 작성할 수 있지만 내부 dict를 사용하는 대신 getattrib() global 메서드를 사용하는 것이 좋습니다.그러면 다음과 같습니다.
def Override(superClass):
def method(func)
getattr(superClass,method.__name__)
return method
getattr()를 원하는 경우 catch catch로 오류를 발생시킬 수 있지만 이 경우 getattr 메서드가 더 좋다고 생각합니다.
또한 클래스 메서드 및 페어러블을 포함한 클래스에 바인딩된 모든 항목도 가져옵니다.
@mkorpela의 훌륭한 답변을 바탕으로, 저는 더 많은 검사를 하는 유사한 패키지(ipromise pypi github)를 작성했습니다.
가정하다A
계승하다B
★★★★★★★★★★★★★★★★★」C
,B
계승하다C
.
모듈 ipromise는 다음 사항을 확인합니다.
if
A.f
「」를B.f
,B.f
해야 하고, 존재해야 합니다.A
B
(이것은 오버라이드 패키지의 체크입니다).문양이 없습니다.
A.f
에 의해 합니다.B.f
후,은, 「」, 「」, 「」, 「」를 것을 선언합니다.C.f
A
C.f
B
는 이 메서드의 덮어쓰기를 정지할 수 있으며 이로 인해 다운스트림업데이트는 발생하지 않습니다.문양이 없습니다.
A.f
에 의해 합니다.C.f
B.f
는 오버라이드를 선언하지 않습니다.문양이 없습니다.
A.f
에 의해 합니다.C.f
B.f
일부에서 오버라이드됨을 선언합니다.D.f
.
또한 추상적인 방법을 구현하고 있는지 확인하고 마킹하기 위한 다양한 기능을 갖추고 있습니다.
PEP 544의 프로토콜을 사용할 수 있습니다.이 방식에서는 인터페이스 구현 관계가 사용자 사이트에서만 선언됩니다.
이 되어 가정합니다.MyFoobar
를 및 가 포함되어 있습니다.이 인터페이스(프로토콜)를 라고 .프로토콜은 구현의 모든 메서드와 필드의 시그니처를 가지고 있습니다.IFoobar
.
그런 다음 사용 사이트에서 구현 인스턴스 바인딩을 인터페이스 유형으로 선언합니다. myFoobar: IFoobar = MyFoobar()
인터페이스에 없는 필드/메서드를 사용하면 사용 사이트에서 Mypy가 불만을 제기합니다(실행시에 동작해도!).구현에서 인터페이스에서 메서드를 구현하지 못한 경우 Mypy도 불만을 제기합니다.인터페이스에 존재하지 않는 것을 구현해도 마이피는 불평하지 않습니다.단, 인터페이스의 정의는 컴팩트하고 검토가 용이하기 때문에 이 경우는 거의 없습니다.마이피가 불평할 테니까 실제로 그 코드를 사용할 수는 없을 거예요.
슈퍼클래스와 실장 클래스 양쪽에서 실장하고 있는 경우는 제외합니다.예를 들어, 의 사용법 등입니다.override
는 인터페이스에 실장되어 있지 않아도 Java에서 사용됩니다.이 솔루션은 그 케이스를 커버합니다.
from typing import Protocol
class A(Protocol):
def b(self):
...
def d(self): # we forgot to implement this in C
...
class C:
def b(self):
return 0
bob: A = C()
형식 확인 결과:
test.py:13: error: Incompatible types in assignment (expression has type "C", variable has type "A")
test.py:13: note: 'C' is missing following 'A' protocol member:
test.py:13: note: d
Found 1 error in 1 file (checked 1 source file)
내가 만든 데코레이터는 슈퍼클래스를 지정하지 않고 덮어쓰기 속성의 이름이 해당 속성이 속한 클래스의 슈퍼클래스인지 여부를 체크했을 뿐만 아니라 덮어쓰기 속성이 덮어쓰기 속성과 동일한 유형인지도 체크합니다.클래스 메서드는 메서드, 스태틱 메서드는 함수처럼 취급됩니다.이 데코레이터는 콜러블, 클래스 메서드, 정적 메서드 및 속성에 대해 작동합니다.
소스 코드에 대해서는, https://github.com/fireuser909/override 를 참조해 주세요.
이 장식기는 재정의 인스턴스인 클래스에 대해서만 작동합니다.OverridesMeta이지만 클래스가 커스텀 메타클래스의 인스턴스인 경우 create_custom_overrides_meta 함수를 사용하여 오버라이드 데코레이터와 호환되는 메타클래스를 만듭니다.테스트의 경우 오버라이드를 실행합니다.__init__ 모듈.
Python 2.6+와 Python 3.2+에서는 가능합니다(실제로 Python은 함수 오버로드를 지원하지 않으며 자녀 클래스는 자동으로 부모의 메서드를 덮어씁니다).데코레이터를 사용하면 됩니다.하지만 먼저, Python은@decorators
Java의 @Annotations
전혀 다른 것들이다.이전 것은 구체적인 코드가 포함된 래퍼이며, 이후 것은 컴파일러에 대한 플래그입니다.
하려면 먼저 하세요.pip install multipledispatch
from multipledispatch import dispatch as Override
# using alias 'Override' just to give you some feel :)
class A:
def foo(self):
print('foo in A')
# More methods here
class B(A):
@Override()
def foo(self):
print('foo in B')
@Override(int)
def foo(self,a):
print('foo in B; arg =',a)
@Override(str,float)
def foo(self,a,b):
print('foo in B; arg =',(a,b))
a=A()
b=B()
a.foo()
b.foo()
b.foo(4)
b.foo('Wheee',3.14)
출력:
foo in A
foo in B
foo in B; arg = 4
foo in B; arg = ('Wheee', 3.14)
여기에서는 괄호 안에 데코레이터를 사용해야 합니다.
가지 은 Python은 때문에 것이 에도 클래스 B 클래스 A가 필요하다는 입니다.foo
@Override를하는 것보다도 이 에일리어스 를하는 것이 좋습니다).s @Override는 'Override'를 사용하는 것이 좋습니다.
python 3.6 이상에서는 python의 기술자 프로토콜을 사용하여 set_name dunder 메서드를 사용하여 @fython에 의해 제공되는 기능을 쉽게 구현할 수 있습니다.
class override:
def __init__(self, func):
self._func = func
update_wrapper(self, func)
def __get__(self, obj, obj_type):
if obj is None:
return self
return self._func
def __set_name__(self, obj_type, name):
self.validate_override(obj_type, name)
def validate_override(self, obj_type, name):
for parent in obj_type.__bases__:
func = parent.__dict__.get(name, None)
if callable(func):
return
else:
raise NotImplementedError(f"{obj_type.__name__} does not override {name}")
여기서 set_name은 wraped 클래스가 정의되면 호출됩니다.wraped 클래스의 부모 클래스는 dunder 메서드 베이스를 호출함으로써 취득할 수 있습니다.
각각의 부모 클래스에 대해서, 우리는 랩된 함수가 클래스에 실장되어 있는지 확인하고 싶다.
- 함수 이름이 클래스 dict에 있는지 확인합니다.
- 그것은 호출할 수 있다
i를 사용하는 방법은 다음과 같습니다.
class AbstractShoppingCartService:
def add_item(self, request: AddItemRequest) -> Cart:
...
class ShoppingCartService(AbstractShoppingCartService):
@override
def add_item(self, request: AddItemRequest) -> Cart:
...
Hear는 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()
언급URL : https://stackoverflow.com/questions/1167617/in-python-how-do-i-indicate-im-overriding-a-method
'programing' 카테고리의 다른 글
Maria DB의 맨 위 행을 제외한 모든 행 선택 (0) | 2023.01.25 |
---|---|
easy_install보다 pip을 사용하는 이유는 무엇입니까? (0) | 2023.01.25 |
__slots__의 사용방법 (0) | 2023.01.25 |
인덱스된 키에 가입하더라도 MySQL(InnoDB) 쿼리가 느립니다. 이유는 무엇입니까? (0) | 2023.01.25 |
오류: (23, 17) 해결 실패: junit: junit: 4.12 (0) | 2023.01.25 |