例如,在Java中,@Override
注释不仅提供了覆盖的编译时检查,而且还提供了出色的自我记录代码。
我只是在寻找文件(尽管如果它是一些像pylint这样的检查器的指示器,那就是奖金)。我可以在某处添加注释或docstring,但是在Python中指示覆盖的惯用方法是什么?
更新(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
它的工作原理如下:
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),否则这实际上只是眼花缭乱。
但是,这就是Python,为什么要把它写成Java呢?
Python不是Java。当然没有像编译时检查那样的东西。
我认为文档字符串中的注释很多。这允许您的方法的任何用户键入help(obj.method)
并查看该方法是一个覆盖。
您还可以使用class Foo(Interface)
显式扩展接口,这将允许用户键入help(Interface.method)
以了解您的方法要提供的功能。
就像其他人说的那样,不像Java那样没有@Overide标签,但是上面你可以创建自己的使用装饰器但是我建议使用getattrib()全局方法而不是使用内部dict,所以你得到类似如下的内容:
def Override(superClass):
def method(func)
getattr(superClass,method.__name__)
return method
如果你想在你自己的尝试中捕获getattr(),请抓住引发自己的错误,但我认为在这种情况下getattr方法更好。
此外,它还捕获绑定到类的所有项,包括类方法和变量
即兴创作@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
"not implemented in base class"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
"expected implemented type"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
错误很快就会被发现。
听听最简单,在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()