51 votes

Méthodes d'extension Python

OK, en C# nous avons quelque chose comme :

 public static string Destroy(this string s) { 
    return "";
}

Donc en gros, quand vous avez une chaîne, vous pouvez faire :

 str = "This is my string to be destroyed";
newstr = str.Destroy()
# instead of 
newstr = Destroy(str)

Maintenant c'est cool parce qu'à mon avis c'est plus lisible. Python a-t-il quelque chose de similaire ? Je veux dire au lieu d'écrire comme ça :

 x = SomeClass()
div = x.getMyDiv()
span = x.FirstChild(x.FirstChild(div)) # so instead of this

j'aimerais écrire :

 span = div.FirstChild().FirstChild() # which is more readable to me

Toute suggestion?

12voto

murgatroid99 Points 5099

Vous pouvez faire ce que vous avez demandé comme suit :

 def extension_method(self):
    #do stuff
class.extension_method = extension_method

8voto

J'utiliserais le modèle Adapter ici. Donc, disons que nous avons une Person et à un endroit spécifique, nous aimerions ajouter des méthodes liées à la santé.

 from dataclasses import dataclass


@dataclass
class Person:
    name: str
    height: float  # in meters
    mass: float  # in kg


class PersonMedicalAdapter:
    person: Person

    def __init__(self, person: Person):
        self.person = person

    def __getattr__(self, item):
        return getattr(self.person, item)

    def get_body_mass_index(self) -> float:
        return self.person.mass / self.person.height ** 2


if __name__ == '__main__':
    person = Person('John', height=1.7, mass=76)
    person_adapter = PersonMedicalAdapter(person)

    print(person_adapter.name)  # Call to Person object field
    print(person_adapter.get_body_mass_index())  # Call to wrapper object method

Je considère que c'est une solution facile à lire, mais flexible et pythonique.

4voto

mrts Points 472

Vous pouvez facilement y parvenir avec le gestionnaire de contexte suivant qui ajoute la méthode à la classe ou à l'objet à l'intérieur du bloc de contexte et la supprime par la suite :

 class extension_method:

    def __init__(self, obj, method):
        method_name = method.__name__
        setattr(obj, method_name, method)
        self.obj = obj
        self.method_name = method_name

    def __enter__(self):
        return self.obj

    def __exit__(self, type, value, traceback):
        # remove this if you want to keep the extension method after context exit
        delattr(self.obj, self.method_name)

L'utilisation est la suivante :

 class C:
    pass

def get_class_name(self):
    return self.__class__.__name__

with extension_method(C, get_class_name):
    assert hasattr(C, 'get_class_name') # the method is added to C
    c = C()
    print(c.get_class_name()) # prints 'C'

assert not hasattr(C, 'get_class_name') # the method is gone from C

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