Dies könnte funktionieren, obwohl ich bin sicher, dass die Grenzfälle, wie zusätzliche Argumente verpassen:
from functools import partial, update_wrapper
def annotate_from(f):
return partial(update_wrapper,
wrapped=f,
assigned=('__annotations__',),
updated=())
die im Auge „Wrapper“ Funktion des __annotations__
Attribut aus f.__annotations__
(halten zuweisen, dass es sich nicht um eine Kopieren).
Nach Unterlagen, die Standardeinstellung des update_wrapper
Funktion für zugewiesen__annotations__
bereits enthält, aber ich kann sehen, warum Sie würden nicht alle anderen Attribute von gewickelt zugewiesen haben wollen.
Mit diesem können Sie dann definieren Sie Ihre Circle
und Rectangle
als
class Circle:
@annotate_from(Shape.area)
def area(self):
return math.pi * self.radius ** 2
class Rectangle:
@annotate_from(Shape.area)
def area(self):
return self.height * self.width
und das Ergebnis
In [82]: Circle.area.__annotations__
Out[82]: {'return': builtins.float}
In [86]: Rectangle.area.__annotations__
Out[86]: {'return': builtins.float}
Als Nebeneffekt Ihre Methoden wird ein Attribut __wrapped__
, haben die zu Shape.area
Punkt wird in dieser Fall.
Eine weniger übliche Weise Umgang mit überschriebene Methoden erreicht werden kann, erreichen (wenn Sie die obige Verwendung von update_wrapper Standard nennen kann) eine Klasse Dekorateur mit:
from inspect import getmembers, isfunction, signature
def override(f):
"""
Mark method overrides.
"""
f.__override__ = True
return f
def _is_method_override(m):
return isfunction(m) and getattr(m, '__override__', False)
def annotate_overrides(cls):
"""
Copy annotations of overridden methods.
"""
bases = cls.mro()[1:]
for name, method in getmembers(cls, _is_method_override):
for base in bases:
if hasattr(base, name):
break
else:
raise RuntimeError(
'method {!r} not found in bases of {!r}'.format(
name, cls))
base_method = getattr(base, name)
method.__annotations__ = base_method.__annotations__.copy()
return cls
und dann:
@annotate_overrides
class Rectangle(Shape):
@override
def area(self):
return self.height * self.width
Auch dies wird überschreiben Methoden mit zusätzlichen Argumenten nicht behandeln.
Awesome, vielen Dank! :) Ich hatte noch nicht mal an Dekorateur gedacht. –