在 Python 中,如何指示我正在重写某个方法?
-
19-09-2019 - |
题
以 Java 为例, @Override
注释不仅提供了重写的编译时检查,而且还提供了优秀的自记录代码。
我只是在寻找文档(尽管如果它是像 pylint 这样的检查器的指示符,那就是一个奖励)。我可以在某处添加注释或文档字符串,但是在 Python 中指示覆盖的惯用方法是什么?
解决方案
<强> UPDATE(2015年5月23日):在此基础上和FWC:的回答我创建画中画安装包的https:// github上的.com / mkorpela /覆盖 强>
从我不时会在这里结束看这个问题。 主要发生这种情况之后(再次)看到在我们的代码库相同的错误:有人已经忘记了一些“接口”实现类而在“界面”重命名的方法..
好了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()全局法,而不是使用内部字典:
def Override(superClass):
def method(func)
getattr(superClass,method.__name__)
return method
如果你想,你可以在自己的尝试捕捉赶上GETATTR()提出自己的错误,但我认为GETATTR方法是在这种情况下更好。
同样在此捕获结合于包括类方法和vairables
的一类的所有项即兴的@mkorpela 伟大的答案,这里是一个版本
更精确的检查,命名和凸起Error对象
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 的精彩回答,我写了一个类似的包(我保证 皮皮 github)执行更多检查:
假设A继承自B和C。并且B继承自C。ipromise 检查
如果A.f覆盖B.f,则B.f必须存在,并且A必须继承自B。(这是来自覆盖包的检查)。
您没有模式 A.f 声明它覆盖 B.f,然后 B.f 声明它覆盖 C.f A 应该说它覆盖 C.f,因为 B 可能决定停止覆盖此方法,并且这不应导致下游更新。
您没有模式 A.f 声明它覆盖 C.f,但 B.f 没有声明它的覆盖。
您没有模式 A.f 声明它覆盖 C.f,但 B.f 声明它覆盖某些 D.f。
它还具有用于标记和检查抽象方法实现的各种功能。
听到的是最简单的和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()