例如,在Java中,@Override注释不仅提供了重写的编译时检查,而且可以生成优秀的自文档代码。
我只是在寻找文档(尽管如果它是一些检查器(如pylint)的指示器,那是额外的奖励)。我可以在某处添加注释或文档字符串,但在Python中指示重写的惯用方法是什么?
例如,在Java中,@Override注释不仅提供了重写的编译时检查,而且可以生成优秀的自文档代码。
我只是在寻找文档(尽管如果它是一些检查器(如pylint)的指示器,那是额外的奖励)。我可以在某处添加注释或文档字符串,但在Python中指示重写的惯用方法是什么?
当前回答
在Python 2.6+和Python 3.2+中,你可以这样做(实际上是模拟的,Python不支持函数重载,子类会自动覆盖父类的方法)。我们可以使用decorator。但首先,请注意Python的@decorators和Java的@Annotations是完全不同的东西。前一个是带有具体代码的包装器,后一个是编译器的标志。
为此,首先执行pip安装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)
注意,这里必须使用带有括号的decorator
需要记住的一件事是,由于Python没有直接的函数重载,所以即使类B没有继承自类A,但需要所有这些foo,也需要使用@Override(尽管在这种情况下使用别名'Overload'会更好看)
其他回答
如果你只是为了文档的目的,你可以定义你自己的覆盖装饰器:
def override(f):
return f
class MyClass (BaseClass):
@override
def method(self):
pass
这实际上只是花瓶,除非你创建override(f)的方式实际上是检查重写。
但是,这是Python,为什么要写成Java呢?
这里是一个没有注释的不同解决方案。
它有一个稍微不同的目标。其他建议的解决方案检查给定的方法是否实际覆盖了父方法,而这个解决方案检查是否所有的父方法都被覆盖了。
你不必引发AssertionError,但可以打印警告或在生产环境中通过检查__init__中的env并在检查之前返回它。
class Parent:
def a():
pass
def b():
pass
class Child(Overrides, Parent):
def a()
# raises an error, as b() is not overridden
class Overrides:
def __init__(self):
# collect all defined methods of all base-classes
bases = [b for b in self.__class__.__bases__ if b != Overrides]
required_methods = set()
for base in bases:
required_methods = required_methods.union(set([f for f in dir(base) if not f.startswith('_')]))
# check for each method in each base class (in required_methods)
# if the class, that inherits `Overrides` implements them all
missing = []
# me is the fully qualified name of the CLASS, which inherits
# `Overrides`
me = self.__class__.__qualname__
for required_method in required_methods:
# The method can be either defined in the parent or the child
# class. To check it, we get a reference to the method via
# getattr
try:
found = getattr(self, required_method)
except AttributeError:
# this should not happen, as getattr returns the method in
# the parent class if it is not defined in the cild class.
# It has to be in a parent class, as the required_methods
# is a union of all base-class methods.
missing.append(required_method)
continue
# here is, where the magic happens.
# found is a reference to a method, and found.__qualname__ is
# the full-name of the METHOD. Remember, that me is the full
# name of the class.
# We want to check, where the method is defined. If it is
# defined in an parent class, we did no override it, thus it
# is missing.
# If we did not override, the __qualname__ is Parent.method
# If we did override it, the __qualname__ is Child.method
# With this fact, we can determine if the class, which uses
# `Override` did implement it.
if not found.__qualname__.startswith(me + '.'):
missing.append(required_method)
# Maybe a warning would be enough here
if missing != []:
raise AssertionError(f'{me} did not override these methods: {missing}')
Python不是Java。当然,没有真正的编译时检查。
我认为文档字符串中的注释就足够了。这允许您的方法的任何用户输入help(obj.method),并看到该方法是一个覆盖。
你也可以用类Foo(interface)显式地扩展一个接口,这将允许用户输入help(interface .method)来了解你的方法想要提供的功能。
在Python 2.6+和Python 3.2+中,你可以这样做(实际上是模拟的,Python不支持函数重载,子类会自动覆盖父类的方法)。我们可以使用decorator。但首先,请注意Python的@decorators和Java的@Annotations是完全不同的东西。前一个是带有具体代码的包装器,后一个是编译器的标志。
为此,首先执行pip安装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)
注意,这里必须使用带有括号的decorator
需要记住的一件事是,由于Python没有直接的函数重载,所以即使类B没有继承自类A,但需要所有这些foo,也需要使用@Override(尽管在这种情况下使用别名'Overload'会更好看)
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()