2010-09-04 5 views
2

Je suis novice en python, et j'ai lu que l'utilisation de global pour passer des variables à d'autres fonctions est considérée comme une mauvaise chose, ainsi qu'une mauvaise pratique. Je voudrais abandonner l'utilisation de variables globales, mais je ne suis pas sûr de savoir quoi faire à la place.Alternative au passage des variables globales autour des classes et des fonctions

À l'heure actuelle, j'ai une interface utilisateur que j'ai créée dans wxPython en tant que sa propre classe distincte, et j'ai une autre classe qui charge les paramètres d'un fichier .ini. Étant donné que les paramètres de l'interface utilisateur doivent correspondre à ceux du fichier .ini, comment puis-je contourner ces valeurs? Je pourrais utiliser quelque chose comme: Settings = Settings() et ensuite définir les variables comme quelque chose comme self.settings1, mais alors je devrais faire Settings une variable globale pour le passer à ma classe d'interface utilisateur (ce ne serait pas si j'attribuer self.settings1).

Alors, quelle est la manière correcte et pythonique de passer ces variables?

Editer: Voici le code avec lequel je travaille, et j'essaie de le faire fonctionner comme l'exemple d'Alex Martelli. Le code suivant est enregistré dans Settings.py:

import ConfigParser 

class _Settings(): 
    @property 
    def enableautodownload(self): return self._enableautodownload 
    def __init__(self): 
     self.config = ConfigParser.ConfigParser() 

     self.config.readfp(open('settings.ini')) 
     self._enableautodownload=self.config.getboolean('DLSettings', 'enableautodownload') 

settings = _Settings() 

Chaque fois que je tente de se référer à Settings.settings.enableautodownload d'un autre fichier que je reçois: AttributeError: 'module' object has no attribute 'settings'. Qu'est-ce que je fais mal?

Éditer 2: Peu importe le problème, j'ai retapé le code et cela fonctionne maintenant, il doit donc s'agir d'une simple faute d'orthographe ou de syntaxe.

+0

Il y a des cas où il est bon d'utiliser des globales, où la gêne occasionnée par la généralité du passage autour d'un objet est largement compensée. Vous devriez éviter cela quand vous commencez, jusqu'à ce que vous ayez une idée du moment approprié. –

+0

semble que l'importation correcte devrait être 'à partir du paramètre d'importation Settings', alors vous pouvez l'utiliser, disons, comme' print settings.enableautodownload'. – flow

Répondre

4

Les alternatives à global variables sont nombreux - la plupart du temps:

  • arguments explicites aux fonctions, classes appelées à créer un de leur instance, etc (ce qui est généralement la plus claire, car elle rend la dépendance la plus explicite , lorsque cela est possible et pas trop répétitif);
  • les variables d'instance d'un objet, lorsque les fonctions qui ont besoin d'accéder à ces valeurs sont des méthodes sur ce même objet (c'est aussi OK, et une manière raisonnable d'utiliser la POO);
  • "fonctions d'accès" qui fournissent les valeurs (ou un objet qui a des attributs ou des propriétés pour les valeurs).

Chacun de ces (esp. Les premiers et troisième) est particulièrement utile pour les valeurs dont les noms doivent pas être lié à nouveau par tout le monde, mais seulement accessible. Le très gros problème avec global est qu'il fournit un "canal de communication caché" (pas dans le sens cryptographique, mais dans le sens littéral: des fonctions apparemment séparées peuvent en fait dépendre les unes des autres, influençant les unes les autres, via des valeurs globales qui ne sont pas "évident" à partir des signatures des fonctions - cela rend le code difficile à tester, déboguer, maintenir et comprendre). Pour votre problème spécifique, si vous n'utilisez jamais l'instruction global, mais accédez plutôt aux paramètres de manière «en lecture seule» de partout (et que vous pouvez en faire plus en rendant les attributs de cet objet des propriétés en lecture seule !), puis avoir les accès "en lecture seule" être effectué sur une instance unique, faite une fois, puis non modifié, au niveau du module, n'est pas trop mauvais. C'est à dire., Dans certains modules foo.py:

class _Settings(object): 
    @property 
    def one(self): return self._one 
    @property 
    def two(self): return self._two 
    def __init__(self, one, two): 
     self._one, self._two = one, two 
settings = _Settings(23, 45) 

et de partout ailleurs, import foo alors seulement l'accès foo.settings.one et foo.settings.two au besoin. Notez que j'ai nommé la classe avec un seul trait de soulignement principal (tout comme les deux attributs d'instance qui sous-tendent les propriétés en lecture seule) pour suggérer qu'il n'est pas destiné à être utilisé de l'extérieur du module - seul l'objet settings est supposé être (il n'y a pas de mise en application - mais tout utilisateur qui viole une telle confidentialité demandée est de toute évidence la seule partie responsable de tout ce qui peut s'ensuivre ;-).

+0

Merci pour l'exemple, mais je n'arrive pas à le faire fonctionner sur mon code. Je l'ai édité dans la question, alors pouvez-vous me dire ce que je fais mal? – FlowofSoul

+0

@Flowof, 'print Settings .__ file__' avant de commencer à essayer d'utiliser' Settings.settings' d'un autre endroit, afin de confirmer * quoi * exactement vous avez importé sous ce nom particulier (les noms de modules mixtes posent souvent des problèmes sous des systèmes de fichiers insensibles à la casse tels que ceux de Windows et certains Mac, ils sont maintenant fortement déconseillés en faveur de ceux en minuscules). Dans le cas surprenant où vous avez réellement importé le bon fichier, ajoutez 'print dir (Settings)' pour voir exactement ce qui est ** défini dans ce fichier. S'il vous plaît modifier votre question pour donner cette information cruciale. –

+0

Tout importait correctement, donc j'ai juste retapé le code et ça fonctionne maintenant. Merci de votre aide. – FlowofSoul

Questions connexes