Blu*_*luu 148 python inheritance overriding self-documenting-code
例如,在Java中,@Override注释不仅提供了覆盖的编译时检查,而且还提供了出色的自我记录代码.
我只是在寻找文件(尽管如果它是一些像pylint这样的检查器的指示器,那就是奖金).我可以在某处添加注释或docstring,但是在Python中指示覆盖的惯用方法是什么?
mko*_*ela 185
更新(2015年5月23日):根据这个和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
Run Code Online (Sandbox Code Playgroud)
它的工作原理如下:
class MySuperInterface(object):
def my_method(self):
print 'hello world!'
class ConcreteImplementer(MySuperInterface):
@overrides(MySuperInterface)
def my_method(self):
print 'hello kitty!'
Run Code Online (Sandbox Code Playgroud)
如果你做了一个错误的版本,它会在类加载期间引发一个断言错误:
class ConcreteFaultyImplementer(MySuperInterface):
@overrides(MySuperInterface)
def your_method(self):
print 'bye bye!'
>> AssertionError!!!!!!!
Run Code Online (Sandbox Code Playgroud)
Lor*_*lli 38
从 python 3.12(发布日期为 2023 年秋季)开始,这是可以完成的。我建议您查看这个网站https://peps.python.org/pep-0698/。它很好地解释了如何像在 Java 中一样在 Python 中修饰方法。
这是一个代码示例,有关更多详细信息,您可以查看上面的网站。
from typing import override
class Parent:
def foo(self) -> int:
return 1
def bar(self, x: str) -> str:
return x
class Child(Parent):
@override
def foo(self) -> int:
return 2
@override
def baz() -> int: # Type check error: no matching signature in ancestor
return 1
Run Code Online (Sandbox Code Playgroud)
fwc*_*fwc 27
这是一个不需要指定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
Run Code Online (Sandbox Code Playgroud)
Ber*_*Ber 13
如果您只想将其用于文档目的,则可以定义自己的覆盖装饰器:
def override(f):
return f
class MyClass (BaseClass):
@override
def method(self):
pass
Run Code Online (Sandbox Code Playgroud)
除非你以实际检查覆盖的方式创建覆盖(f),否则这实际上只是眼花缭乱.
但是,这就是Python,为什么要把它写成Java呢?
Python不是Java.当然没有像编译时检查那样的东西.
我认为文档字符串中的注释很多.这允许您的方法的任何用户键入help(obj.method)并查看该方法是覆盖.
您还可以使用显式扩展接口class Foo(Interface),这将允许用户键入help(Interface.method)以了解您的方法要提供的功能.
即兴创作@mkorpela很好的答案,这里有一个版本
def overrides(interface_class):
"""
Function override annotation.
Corollary to @abc.abstractmethod where the override is not of an
abstractmethod.
Modified from answer /sf/answers/581912971/
"""
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
Run Code Online (Sandbox Code Playgroud)
下面是它在实践中的样子:
NotImplementedError“未在基类中实现”class A(object):
# ERROR: `a` is not a implemented!
pass
class B(A):
@overrides(A)
def a(self):
pass
Run Code Online (Sandbox Code Playgroud)
导致更多描述性NotImplementedError错误
function "a" is an @override but that function is not implemented in base class <class '__main__.A'>
Run Code Online (Sandbox Code Playgroud)
全栈
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'>
Run Code Online (Sandbox Code Playgroud)
NotImplementedError“预期实现类型”class A(object):
# ERROR: `a` is not a function!
a = ''
class B(A):
@overrides(A)
def a(self):
pass
Run Code Online (Sandbox Code Playgroud)
导致更多描述性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'>
Run Code Online (Sandbox Code Playgroud)
全栈
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'>
Run Code Online (Sandbox Code Playgroud)
@mkorpela 答案的好处是检查发生在某个初始化阶段。检查不需要“运行”。参考前面的示例,class B从未初始化 ( B()) 但NotImplementedError仍然会引发。这意味着overrides可以更快地发现错误。
| 归档时间: |
|
| 查看次数: |
62319 次 |
| 最近记录: |