web-dev-qa-db-fra.com

Objectif de «retourner soi-même» à partir d'une méthode de classe?

Je suis tombé sur quelque chose comme ça dans un projet open-source. Les méthodes qui modifient les attributs d'instance renvoient une référence à l'instance. Quel est le but de cette construction?

class Foo(object):

  def __init__(self):
    self.myattr = 0

  def bar(self):
    self.myattr += 1
    return self
46
nate c

C'est pour permettre le chaînage.

Par exemple:

var Car = function () {
    return {
        gas : 0,
        miles : 0,
        drive : function (d) {
            this.miles += d;
            this.gas -= d;
            return this;
        },
        fill : function (g) {
            this.gas += g;
            return this;
        },
    };
}

Vous pouvez maintenant dire:

var c = Car();
c.fill(100).drive(50);
c.miles => 50;
c.gas => 50;
66
Josh K

Comme le mentionnent @Lie Ryan et @Frank Shearar, cela s'appelle une "interface fluide" mais ce modèle existe depuis très longtemps.

La partie controversée de ce modèle est qu'en OO, vous avez un état mutable, donc une méthode void a une sorte de valeur de retour implicite de this - c'est-à-dire que l'objet avec l'état mis à jour est une sorte de valeur de retour .

Donc dans un langage OO avec état mutable, ces deux sont plus ou moins équivalents:

a.doA()
a.doB()
a.doC()

... par opposition à

a.doA().doB().doC()

J'ai donc entendu des gens dans le passé résister à des interfaces fluides parce qu'ils aiment la première forme. Un autre nom que j'ai entendu pour "interface fluide" est "épave de train";)

Je dis "plus ou moins équivalent", car les interfaces fluides ajoutent une ride. Ils n'ont pas à "retourner cela". Ils peuvent "retourner neuf". C'est une façon d'atteindre des objets immuables en OO.

Vous pourriez donc avoir une classe A qui le fait (pseudocode)

function doA():
    return new A(value + 1)

function doB():
    return new A(value * 2)

function doC():
    return new A(sqrt(value))

Désormais, chaque méthode renvoie un nouvel objet, sans modifier l'objet initial. Et c'est une façon d'entrer dans des objets immuables sans vraiment changer grand chose dans votre code.

10
Rob

La plupart des langages sont conscients de l'idiome de "retour de soi" et l'ignorent s'il n'est pas utilisé dans une ligne. Cependant, il est à noter qu'en Python, les fonctions retournent None par défaut.

Quand j'étais à l'école CS, mon instructeur a fait un énorme accord sur la différence entre les fonctions, les procédures, les routines et les méthodes; de nombreuses questions sur les crampes à la main ont été rectifiées avec des crayons mécaniques qui chauffaient dans mes mains à propos de tout cela.

Il suffit de dire que le retour de self est le moyen définitif OO pour créer des méthodes de classe, mais Python permet plusieurs valeurs de retour, tuples, listes, objets, primitives) ou Aucun.

Le chaînage, comme ils le disent, consiste simplement à mettre la réponse à la dernière opération dans la suivante, et le temps d'exécution de Python peut optimiser ce genre de chose. Les compréhensions de liste sont une forme intégrée de ceci. (Très puissant!)

Donc dans Python il n'est pas si important que chaque méthode ou fonction retourne des choses, c'est pourquoi la valeur par défaut est None.

Il y a une école de pensée selon laquelle chaque action dans un programme devrait rapporter son succès, son échec ou son résultat dans son contexte ou son objet d'invocation, mais ne parlait pas des exigences DOD ADA ici. Si vous avez besoin d'obtenir des commentaires sur une méthode, allez-y ou non, mais essayez d'être cohérent à ce sujet.

Si une méthode peut échouer, elle doit retourner succès ou échec ou déclencher une exception à gérer.

Une mise en garde est que si vous utilisez l'idiome de retour auto, Python vous permettra d'affecter toutes vos méthodes aux variables et vous pourriez penser que vous obtenez un résultat de données ou une liste lorsque vous obtenez réellement L'object.

Les langages à restriction de type crient, crient et se brisent lorsque vous essayez de le faire, mais les langages interprétés (Python, Lua, LISP) sont beaucoup plus dynamiques.

8
Chris Reid

Dans Smalltalk, chaque méthode qui ne retourne pas explicitement quelque chose, a un "return self" implicite.

C'est parce que (a) le fait que chaque méthode renvoie quelque chose rend le modèle informatique plus uniforme et (b) il est très utile que les méthodes retournent elles-mêmes. Josh K donne un bel exemple.

4
Frank Shearar

Avantages du retour d'un objet (return self)

  • Exemple:

    print(foo.modify1().modify2())
    
    # instaed of
    foo.modify1()
    foo.modify2()
    print(foo)
    
  • Style plus populaire dans la communauté de programmation (je pense).

Avantages de la mutation d'un objet (pas de return self)

  • Possibilité d'utiliser return à d'autres fins.
  • Guido van Rossum approuve ce style (je suis en désaccord avec son argument).
  • Style plus populaire dans la communauté Python (je pense).
  • Par défaut (moins de code source).
2
xged