web-dev-qa-db-fra.com

Comment éviter le "moi" explicite en Python?

J'ai appris Python en suivant quelques tutoriels pygame .

Dans celui-ci, j’ai trouvé un usage intensif du mot-clé self, et provenant d’un arrière-plan principalement Java, j’ai oublié d’oublier de taper self. Par exemple, au lieu de self.rect.centerx, je taperais rect.centerx car, pour moi, rect est déjà une variable membre de la classe.

Le parallèle Java auquel je peux penser pour cette situation est de devoir préfixer toutes les références aux variables membres avec this.

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

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

J'ai jeté un coup d'oeil à ces questions connexes SO, mais elles ne répondent pas tout à fait à ce que je suis après:

97
bguiz

Python nécessite une spécification de soi. 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 sans la définition complète de la classe. Cela conduit à des propriétés utiles, telles que: vous ne pouvez pas ajouter de membres qui occultent accidentellement des non-membres et rompent ainsi le code.

Un exemple extrême: vous pouvez écrire une classe sans avoir la moindre idée de ses classes de base 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 code complet! (some_function renvoie le type utilisé comme base.)

Une 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 les aspects de soi explicitement requis.

84
Roger Pate

En fait, self n'est pas un mot-clé, c'est simplement le nom donné conventionnellement 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 une méthode dispose pour savoir à quelle instance de la classe elle est appelée.

23
Michał Marczyk

Vous pouvez utiliser le nom de votre choix, 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, sauf si vous avez une raison convaincante, car cela le rendrait étranger aux pythonistes expérimentés. 

21
Esteban Küber

oui, vous devez toujours spécifier self, car explicite vaut mieux qu'implicite, selon la philosophie python.

Vous découvrirez également que la façon dont vous programmez en python est très différente de la façon dont vous programmez en Java. Par conséquent, l'utilisation de self tend à diminuer car vous ne projetez pas tout dans l'objet. Vous utilisez plutôt davantage la fonction au niveau du module, qui peut être mieux testée.

au fait. Je détestais ça au début, maintenant je déteste le contraire. idem pour le contrôle de flux indenté.

9
Stefano Borini

Les réponses précédentes sont essentiellement 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 toujours sans réponse. 

En outre, il y a des raisons légitimes pour lesquelles une personne pourrait vouloir faire quelque chose dans le sens de la question posée. Une chose que je rencontre parfois est la longueur des équations mathématiques, où l’utilisation de noms longs rend l’équation non reconnaissable. Voici quelques exemples de solutions possibles:

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) - correspond essentiellement à ce que la question demande, mais permettez-moi de préciser que je ne pense pas que ce soit généralement une bonne idée.

Pour plus d'informations et pour savoir comment parcourir les variables de classe, voire les fonctions, voir les réponses et la discussion à cette question . Pour une discussion sur les autres moyens de nommer des variables de manière dynamique, et pourquoi ce n’est généralement pas une bonne idée, voir cet article de blog .

8
argentum2f

self fait partie de la syntaxe python pour accéder aux membres des objets, donc j'ai bien peur que vous soyez coincé avec elle

5
Charles Ma

Le "self" est l'espace réservé conventionnel de l'instance d'objet en cours d'une classe. Il est utilisé lorsque vous souhaitez faire référence à la propriété, au champ ou à la méthode de l'objet dans une classe, comme si vous vous référiez à "lui-même". Mais pour le rendre plus court, quelqu'un dans le domaine de la programmation Python a commencé à utiliser "self", les autres royaumes utilisent "this" mais le font comme un mot clé qui ne peut pas être remplacé. J'ai plutôt utilisé "son" pour augmenter la lisibilité du code. C'est l'une des bonnes choses en Python - vous avez la liberté de choisir votre propre espace réservé pour l'instance de l'objet autre que "self" . Exemple pour self:

class UserAccount():    
    def __init__(self, user_type, username, password):
        self.user_type = user_type
        self.username = username            
        self.password = encrypt(password)        

    def get_password(self):
        return decrypt(self.password)

    def set_password(self, password):
        self.password = encrypt(password)

Maintenant, nous remplaçons 'self' par 'its':

class UserAccount():    
    def __init__(its, user_type, username, password):
        its.user_type = user_type
        its.username = username            
        its.password = encrypt(password)        

    def get_password(its):
        return decrypt(its.password)

    def set_password(its, password):
        its.password = encrypt(password)

qui est plus lisible maintenant?

5
LEMUEL ADANE

En fait, vous pouvez utiliser la recette "Implicit du moi" de la présentation d'Armin Ronacher "5 ans de mauvaises idées" (google it).

C'est une recette très intelligente, comme presque tout d'Armin Ronacher, mais je ne pense pas que cette idée soit très séduisante. Je pense que je préférerais explicitement this en C #/Java.

Mettre à jour. Lien vers "recette mauvaise idée": https://speakerdeck.com/mitsuhiko/5-years-of-bad-ideas?slide=58

1
Alex Yu

Oui, le moi est fastidieux. Mais est-ce mieux?

class Test:

    def __init__(_):
        _.test = 'test'

    def run(_):
        print _.test
1
user804830

De: Self Hell - Plus de fonctions avec état.

... Une approche hybride donne de meilleurs résultats. Toutes vos méthodes de classe qui réellement Le calcul doit être déplacé dans les fermetures et les extensions pour nettoyer la syntaxe doivent être conservées dans les classes. Farcir les fermetures en classes, traiter la classe un peu comme un espace de noms. Les fermetures sont essentiellement des fonctions statiques, et ne nécessitent donc pas de selfs *, même dans la classe ...

0
user5554473