257 votes

En Python, comment indiquer que je remplace une méthode?

En Java, par exemple, l'annotation @Override permet non seulement de vérifier le remplacement au moment de la compilation, mais constitue également un excellent code auto-documenté. Je suis juste à la recherche de documentation (mais si c'est un indicateur pour un vérificateur comme pylint, c'est un bonus). Je peux ajouter un commentaire ou une docstring quelque part, mais quel est le moyen idiomatique d'indiquer un remplacement en Python?

268voto

mkorpela Points 1441

De temps à autre, je termine ici en regardant cette question. La plupart de ce qui se passe après (encore une fois) de voir le même bug dans notre base de code: Quelqu'un a oublié une partie "interface" mise en œuvre de la classe lors du renommage d'une méthode dans la partie "interface"..

Bien Python, c'est pas du Java mais Python a le pouvoir-et explicite est mieux qu'implicite -- et il y a de vrais cas concrets dans le monde réel, où cette chose m'aurait aidée.

Voici donc une esquisse de remplacements décorateur. Cela permettra de vérifier que la classe passée en paramètre a la même méthode (ou quelque chose) nom de la méthode décoré.

Si vous pouvez penser à une meilleure solution s'il vous plaît poster ici!

def overrides(interface_class):
    def overrider(method):
        assert(method.__name__ in dir(interface_class))
        return method
    return overrider

Il fonctionne comme suit:

class MySuperInterface(object):
    def my_method(self):
        print 'hello world!'


class ConcreteImplementer(MySuperInterface):
    @overrides(MySuperInterface)
    def my_method(self):
        print 'hello kitty!'

et si vous faites une version défectueuse, il déclenche une erreur d'assertion lors du chargement des classes:

class ConcreteFaultyImplementer(MySuperInterface):
    @overrides(MySuperInterface)
    def your_method(self):
        print 'bye bye!'

>> AssertionError!!!!!!!

31voto

fwc Points 101

Voici une implémentation qui ne nécessite pas la spécification du nom 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
 

24voto

Ber Points 10364

Si vous souhaitez utiliser ceci uniquement à des fins de documentation, vous pouvez définir votre propre décorateur de remplacement:

 def override(f):
    return f


class MyClass (BaseClass):

    @override
    def method(self):
        pass
 

Ce n’est vraiment rien d’utile, à moins que vous ne créiez un remplacement (f) de telle sorte qu’il vérifie en fait un remplacement.

Mais alors, c'est Python, pourquoi l'écrire comme si c'était Java?

4voto

Triptych Points 70247

Python n'est pas Java. Bien entendu, il n’existe vraiment pas de vérification au moment de la compilation.

Je pense qu'un commentaire dans le docstring suffit. Cela permet à tout utilisateur de votre méthode de taper help(obj.method) et de voir que la méthode est une substitution.

Vous pouvez également explicitement étendre une interface avec class Foo(Interface) , ce qui permettra aux utilisateurs de taper help(Interface.method) pour avoir une idée de la fonctionnalité que votre méthode est censée fournir.

3voto

Sasha Chedygov Points 36783

Autant que je sache, il n'y a pas de moyen spécial d'indiquer une substitution en Python. Vous venez de définir la méthode et d'inclure une chaîne de caractères, comme toujours.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X