148 votes

Comment éviter le " self " explicite en Python ?

J'ai appris Python en suivant quelques tutoriels pygame .

J'y ai trouvé une utilisation intensive du mot-clé self et venant d'un milieu principalement Java, je trouve que je continue à oublier de taper self . Par exemple, au lieu de self.rect.centerx Je taperais rect.centerx parce que, pour moi, rect est déjà une variable membre de la classe.

Le parallèle Java auquel je peux penser pour cette situation est d'avoir à préfixer toutes les références aux variables de membre avec este .

Suis-je obligé de préfixer toutes les variables membres avec self ou existe-t-il un moyen de les déclarer qui me permettrait d'éviter de devoir le faire ?

Même si ce que je suggère n'est pas pythonique mais j'aimerais quand même savoir si c'est possible.

J'ai jeté un coup d'œil à ces questions connexes sur la SO, mais elles ne répondent pas tout à fait à ce que je cherche :

6 votes

Je viens d'un milieu Java et je trouve cela naturel, mais j'ajoute explicitement "this" à chaque appel pour qu'il soit plus clair que je me réfère à une variable d'instance.

4 votes

Connaissez-vous la convention d'un m_ pour tous les noms de membres, observé par certains programmeurs C++/Java ? L'utilisation de self. contribue de la même manière à la lisibilité. Vous devriez également lire dirtsimple.org/2004/12/python-n'est-pas-java.html .

2 votes

Bien que généralement m_ est utilisé uniquement pour les membres de données non statiques non publics (du moins en C++).

106voto

Python exige de spécifier self. Le résultat est qu'il n'y a jamais de confusion sur ce qui est un membre et ce qui ne l'est pas, même si la définition complète de la classe n'est pas visible. Cela conduit à des propriétés utiles, telles que : vous ne pouvez pas ajouter des membres qui font accidentellement de l'ombre à des non-membres et ainsi casser le code.

Un exemple extrême : vous pouvez écrire une classe sans savoir quelles classes de base elle peut avoir, et toujours savoir si vous accédez à un membre ou non :

class A(some_function()):
  def f(self):
    self.member = 42
    self.method()

C'est le complet code ! (some_function retourne le type utilisé comme base).

Un autre, où les méthodes d'une classe sont composées dynamiquement :

class B(object):
  pass

print B()
# <__main__.B object at 0xb7e4082c>

def B_init(self):
  self.answer = 42
def B_str(self):
  return "<The answer is %s.>" % self.answer
# notice these functions require no knowledge of the actual class
# how hard are they to read and realize that "members" are used?

B.__init__ = B_init
B.__str__ = B_str

print B()
# <The answer is 42.>

N'oubliez pas que ces deux exemples sont extrêmes et que vous ne les verrez pas tous les jours. Je ne suggère pas non plus que vous devriez souvent écrire du code comme celui-ci, mais ils montrent clairement que certains aspects du soi sont explicitement requis.

5 votes

Merci. Cette réponse fait mouche, car elle explique également les avantages de l'utilisation de la technologie de l'information. self .

3 votes

@Roger Pate : Veuillez cesser d'éditer ma question pour en retirer python. Je pense qu'il y a sa place. (et merci pour la réponse !)

3 votes

@bguiz : C'est une convention SO de ne pas dupliquer les balises dans le titre. Cependant, lorsque j'ai édité il y a 2 jours, je n'ai pas vu que vous aviez inversé le titre il y a 7 mois.

55voto

argentum2f Points 685

Les réponses précédentes sont toutes des variantes de "vous ne pouvez pas" ou "vous ne devriez pas". Bien que je sois d'accord avec ce dernier sentiment, la question reste techniquement sans réponse.

En outre, il existe des raisons légitimes pour lesquelles quelqu'un pourrait vouloir faire quelque chose allant dans le sens de ce que la question actuelle demande. Je rencontre parfois de longues équations mathématiques pour lesquelles l'utilisation de noms longs rend l'équation méconnaissable. Voici quelques façons de procéder dans un exemple concret :

import numpy as np
class MyFunkyGaussian() :
    def __init__(self, A, x0, w, s, y0) :
        self.A = float(A)
        self.x0 = x0
        self.w = w
        self.y0 = y0
        self.s = s

    # The correct way, but subjectively less readable to some (like me) 
    def calc1(self, x) :
        return (self.A/(self.w*np.sqrt(np.pi))/(1+self.s*self.w**2/2)
                * np.exp( -(x-self.x0)**2/self.w**2)
                * (1+self.s*(x-self.x0)**2) + self.y0 )

    # The correct way if you really don't want to use 'self' in the calculations
    def calc2(self, x) :
        # Explicity copy variables
        A, x0, w, y0, s = self.A, self.x0, self.w, self.y0, self.s
        sqrt, exp, pi = np.sqrt, np.exp, np.pi
        return ( A/( w*sqrt(pi) )/(1+s*w**2/2)
                * exp( -(x-x0)**2/w**2 )
                * (1+s*(x-x0)**2) + y0 )

    # Probably a bad idea...
    def calc3(self, x) :
        # Automatically copy every class vairable
        for k in self.__dict__ : exec(k+'= self.'+k)
        sqrt, exp, pi = np.sqrt, np.exp, np.pi
        return ( A/( w*sqrt(pi) )/(1+s*w**2/2)
                * exp( -(x-x0)**2/w**2 )
                * (1+s*(x-x0)**2) + y0 )

g = MyFunkyGaussian(2.0, 1.5, 3.0, 5.0, 0.0)
print(g.calc1(0.5))
print(g.calc2(0.5))
print(g.calc3(0.5))

Le troisième exemple - c'est-à-dire l'utilisation de for k in self.__dict__ : exec(k+'= self.'+k) est en fait ce que la question demande, mais laissez-moi être clair : je ne pense pas que ce soit une bonne idée en général.

Pour plus d'informations, et pour connaître les moyens d'itérer à travers les variables de classe, ou même les fonctions, voir les réponses et la discussion sur cette question . Pour une discussion sur les autres façons de nommer dynamiquement des variables, et sur les raisons pour lesquelles ce n'est généralement pas une bonne idée, voir cet article de blog .

UPDATE : Il semble y avoir pas du tout pour mettre à jour ou changer dynamiquement les locales d'une fonction dans Python3, donc calc3 et les variantes similaires ne sont plus possibles. La seule solution compatible avec Python3 à laquelle je pense pour l'instant est l'utilisation de globals :

def calc4(self, x) :
        # Automatically copy every class variable in globals
        globals().update(self.__dict__)
        sqrt, exp, pi = np.sqrt, np.exp, np.pi
        return ( A/( w*sqrt(pi) )/(1+s*w**2/2)
                * exp( -(x-x0)**2/w**2 )
                * (1+s*(x-x0)**2) + y0 )

Ce qui, encore une fois, serait une pratique terrible en général.

8 votes

Brillant ! C'est la réponse la plus (la seule ?) correcte. +1 Vous donnez également une raison pratique unique de le faire. +1i

2 votes

Après avoir créé une classe et déplacé le code à l'intérieur de celle-ci : maintenant, toutes les méthodes et variables ne sont plus reconnues (pas d'identification de la classe). soi. ..) Cela me rappelle une autre raison pour laquelle python et moi ne nous entendons pas. Merci pour cette idée. Elle ne résout pas le problème / le mal de tête / l'illisibilité dans son ensemble mais fournit une solution de rechange modeste.

0 votes

Pourquoi ne pas simplement mettre à jour locals au lieu d'utiliser exec ?

33voto

Michał Marczyk Points 54179

En fait, self n'est pas un mot-clé, c'est juste le nom donné par convention au premier paramètre des méthodes d'instance en Python. Et ce premier paramètre ne peut pas être ignoré, car c'est le seul mécanisme dont dispose une méthode pour savoir sur quelle instance de votre classe elle est appelée.

3 votes

Cette réponse, en particulier la deuxième phrase, est beaucoup plus utile que la réponse acceptée pour moi, car je sais que "explicit self" est juste une des limitations de Python et qu'elle ne peut être évitée.

21voto

voyager Points 17283

Vous pouvez utiliser le nom que vous voulez, par exemple

class test(object):
    def function(this, variable):
        this.variable = variable

ou même

class test(object):
    def function(s, variable):
        s.variable = variable

mais vous êtes obligé d'utiliser un nom pour la portée.

Je ne vous recommande pas d'utiliser quelque chose de différent de vous-même, à moins que vous n'ayez une raison convaincante, car cela le rendrait étranger aux pythonistes expérimentés.

27 votes

Vous pouvez le faire, mais Ne le fais pas. ! Il n'y a aucune raison de rendre votre code plus bizarre qu'il ne doit l'être. Oui, vous pouvez l'appeler comme vous voulez, mais la convention est de l'appeler self et vous devez respecter cette convention. Cela rendra votre code plus facile à comprendre pour tout programmeur Python expérimenté qui le regardera. (Cela vous inclut, dans six mois, lorsque vous essayerez de comprendre ce que fait votre ancien programme).

3 votes

Encore plus étranger : def function(_, variable): _.variable = variable

1 votes

@BobStein-VisiBone encore plus alien : def funcion(*args): args[0].variable = args[1]

9voto

Stefano Borini Points 36904

Oui, vous devez toujours spécifier self car l'explicite est meilleur que l'implicite, selon la philosophie de Python.

Vous découvrirez également que la manière de programmer en python est très différente de la manière de programmer en java, d'où l'utilisation de self a tendance à diminuer car on ne projette pas tout à l'intérieur de l'objet. Au contraire, vous utilisez davantage les fonctions au niveau du module, qui peuvent être mieux testées.

d'ailleurs. Je l'ai détesté au début, maintenant je déteste le contraire. Même chose pour le contrôle de flux avec indentation.

2 votes

"Vous utilisez davantage les fonctions au niveau des modules, qui peuvent être mieux testées" est douteux, et je ne suis pas du tout d'accord. Il est vrai que vous n'êtes pas obligé de faire de tout une méthode (statique ou non) d'une classe, indépendamment du fait que ce soit "logiquement au niveau du module", mais cela n'a rien à voir avec le soi et n'a pas d'impact significatif sur les tests dans un sens ou dans l'autre (pour moi).

0 votes

Elle découle de mon expérience. Je ne le suis pas comme un mantra à chaque fois, mais cela rend les choses plus faciles à tester si vous mettez tout ce qui ne nécessite pas l'accès à une variable membre comme une méthode séparée et indépendante. Oui, vous séparez la logique des données, ce qui oui, est contre la POO, mais ils sont ensemble, juste au niveau du module. Je ne donne pas à l'une ou l'autre la note "meilleure", c'est juste une question de goût. Parfois, je me retrouve à spécifier des méthodes de classe qui n'ont rien à voir avec la classe elle-même, puisqu'elles ne touchent pas à la logique de la classe. self de quelque manière que ce soit. Alors quel est l'intérêt de les avoir dans la classe ?

0 votes

Je ne suis pas d'accord avec les deux parties de cette phrase (il semble que je n'utilise pas plus souvent les "non-méthodes" que dans d'autres langues), mais "qui peut être mieux testé" implique qu'une méthode est supérieure à l'autre (c'est juste la façon dont je l'ai lu ? cela ne semble pas probable), alors que je ne trouve pas de soutien pour cela dans mon expérience. Notez que je ne dis pas que vous devriez toujours utiliser l'un ou l'autre, je dis seulement que les méthodes et les non-méthodes sont également capables d'être testées.

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