Pour expliquer l'excellent @ codelogic réponse, je vous propose une approche plus explicite.C'est la même technique que l'opérateur .
approfondit pour lier une méthode de classe lorsque vous y accédez en tant qu'attribut d'instance, sauf que votre méthode sera en fait une fonction définie en dehors d'une classe.
En utilisant le code de @ codelogic, la seule différence réside dans la manière dont la méthode est liée. J'utilise le fait que les fonctions et les méthodes ne sont pas des données descriptors en Python, et en invoquant la méthode __get__
. Notez en particulier que l'original et le remplacement ont des signatures identiques, ce qui signifie que vous pouvez écrire le remplacement en tant que méthode de classe complète, en accédant à tous les attributs d'instance via self
. En affectant la méthode liée à un attribut d'instance, vous avez créé une simulation presque complète de substitution d'une méthode. Une caractéristique pratique qui manque est l'accès à la version sans-argument de super
, puisque vous n'êtes pas dans une définition de classe. Une autre chose est que l'attribut __name__
de votre méthode liée ne prendra pas le nom de la fonction qu'elle surcharge, comme ce serait le cas dans la définition de classe, mais vous pouvez toujours le définir manuellement. La troisième différence est que votre méthode liée manuellement est une référence d'attribut simple qui se trouve être une fonction. L'opérateur .
ne fait que récupérer cette référence. Lorsque vous invoquez une méthode régulière à partir d'une instance, le processus de liaison crée une nouvelle méthode liée à chaque fois. La seule raison pour laquelle cela fonctionne est que les attributs d'instance remplacent descripteurs non-data. Les descripteurs de données ont __set__
méthodes, quelles méthodes (heureusement pour vous) ne le font pas. Les descripteurs de données de la classe sont prioritaires sur les attributs d'instance. C'est pourquoi vous pouvez assigner à une propriété: leur méthode __set__
est invoquée lorsque vous essayez de faire une affectation. Personnellement, j'aime aller un peu plus loin et cacher la valeur réelle de l'attribut sous-jacent dans __dict__
de l'instance, où il est inaccessible par des moyens normaux exactement parce que la propriété l'ombre.
Vous devez également garder à l'esprit que cela est inutile pour magic (double underscore) methods. Les méthodes magiques peuvent bien sûr être remplacées de cette manière, mais les opérations qui les utilisent ne regardent que le type. Par exemple, vous pouvez définir __contains__
pour quelque chose de spécial dans votre instance, mais l'appel x in instance
ne tiendra pas compte de cela et utilisera type(instance).__contains__(instance, x)
à la place. Ceci s'applique à toutes les méthodes magiques spécifiées dans le Python data model.
@arivero: Je pensais que le "S'il vous plaît ne pas le faire comme le montre" fait parfaitement clair. Quels autres mots aimeriez-vous voir pour clarifier le fait que cela ne répond pas à la question posée, mais donne des conseils sur les raisons pour lesquelles c'est une mauvaise idée? –
Je ne suis pas en désaccord dans le conseil, ni le OP comme il semble. Mais je suppose que les gens ont des raisons de demander. Ou même si le PO n'a pas, d'autres futurs visiteurs pourraient. Donc, à mon humble avis, une réponse plus une réprimande est préférable que juste une réprimande. – arivero
@arivero: Cela n'a pas répondu à ma question. –