2009-07-22 57 views
98

例如,在Java中,@Override注释不仅提供了覆盖的编译时检查,而且还提供了优秀的自写文档代码。我只是在寻找文档(尽管如果它是像pylint这样的检查器的指示器,那是一个奖励)。我可以在某处添加注释或文档字符串,但是在Python中指示重写的惯用方式是什么?在Python中,我如何表明我重写了一个方法?

+10

换句话说,你永远不表明你压倒一种方法?让读者自己弄清楚这一点? – Bluu 2009-07-22 23:49:43

+2

是的,我知道它似乎是一种来自编译语言的容易出错的情况,但您只需接受它。在实践中,我没有发现它是一个很大的问题(在我的情况下,Ruby,而不是Python,但同样的想法) – 2009-07-23 17:12:55

+0

当然,完成。 Triptych的答案和mkorpela的答案都很简单,我喜欢这个,但是后者的明显超越隐含的精神,并且明显地防止错误获胜。 – Bluu 2013-10-17 16:07:47

回答

140

更新(2015年5月23日):在此基础上与FWC:的答案我创建了一个点子安装包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!!!!!!! 
4

据我所知,在Python中没有特别的方式来表示重写。您只需定义方法并像往常一样包含文档字符串。

8

Python不是Java。编译时检查当然没有这样的事情。

我认为在文档字符串中的评论很多。这允许您的方法的任何用户键入help(obj.method)并查看该方法是一个覆盖。

您还可以使用class Foo(Interface)明确扩展接口,这将允许用户输入help(Interface.method)以了解您的方法旨在提供的功能。

+40

Java中`@ Override`的真正意义在于不会记录文件 - 当你打算重写一个方法时,会发现一个错误,但最终会定义一个新文件(例如,因为拼写错了一个名称;在Java中,它可能会也因为您使用了错误的签名而发生,但这在Python中不是问题 - 但拼写错误仍然存​​在)。 – 2009-07-22 19:35:00

8

如果你想这样的文档,仅供参考,您可以定义自己的覆盖装饰:

def override(f): 
    return f 


class MyClass (BaseClass): 

    @override 
    def method(self): 
     pass 

这真的不算什么,但养眼的,除非你创建倍率(F)以这样一种方式,是实际上检查覆盖。

但是,这是Python,为什么写它像Java?

21

这里有没有一个实现需要指定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 
2

像其他人说,Java不同没有@Overide标签上方。然而,你可以创建自己使用的装饰,但是我会建议使用getattrib()全局法,而不是使用内部字典所以你喜欢的东西以下内容:

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

如果你想你能赶上GETATTR()在自己的尝试捕捉提高自己的错误,但我认为GETATTR方法是在这种情况下更好。

另外这款捕捉必然包括类方法的类的所有项目和vairables

0

听到的是最简单和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() 
相关问题