Question

La variable __ debug __ est utile en partie car elle affecte tous les modules. Si je veux créer une autre variable qui fonctionne de la même manière, comment pourrais-je le faire?

La variable (appelons-la 'original' et foo) n'a pas besoin d'être vraiment globale, en ce sens que si je change foo dans un module, elle est mise à jour dans d'autres. Je serais bien si je pouvais définir foo avant d'importer d'autres modules et qu'ils verraient la même valeur.

Était-ce utile?

La solution

Je n’approuve en aucune manière cette solution. Mais si vous ajoutez une variable au module __ built __ , elle sera accessible comme si elle était une variable globale à partir de tout autre module incluant __ built __ - ce qui correspond à toutes, par défaut. .

a.py contient

print foo

b.py contient

import __builtin__
__builtin__.foo = 1
import a

Le résultat est que " 1 " est imprimé.

Modifier: Le module __ construit __ est disponible en tant que symbole local __ construit __ - c'est la raison de la différence entre deux de ces réponses. Notez également que __ built__ __ a été renommé en builtins dans python3.

Autres conseils

Si vous avez besoin d'une variable globale inter-modules, une simple variable globale au niveau du module suffira peut-être.

a.py:

var = 1

b.py:

import a
print a.var
import c
print a.var

c.py:

import a
a.var = 2

Test:

$ python b.py
# -> 1 2

Exemple concret: Le fichier global_settings.py de Django (bien que dans Django les paramètres soient utilisés pour importer l'objet django.conf.settings ).

Définissez un module (appelez-le "globalbaz") et indiquez les variables qui y sont définies. Tous les modules utilisant ce "pseudoglobal" doit importer le " globalbaz " module, et y faire référence en utilisant "globalbaz.var_name"

Cela fonctionne quel que soit le lieu du changement. Vous pouvez modifier la variable avant ou après l'importation. Le module importé utilisera la dernière valeur. (J'ai testé cela dans un exemple de jouet)

À des fins de clarification, globalbaz.py ressemble à ceci:

var_name = "my_useful_string"

Je pense qu'il existe de nombreuses circonstances dans lesquelles il est logique et simplifie la programmation de disposer de globals connus dans plusieurs modules (étroitement couplés). Dans cet esprit, je voudrais développer un peu l'idée d'un module de globals importé par les modules qui doivent les référencer.

Lorsqu'il n'y a qu'un seul module de ce type, je l'appelle "g". J'y attribue des valeurs par défaut pour chaque variable que je souhaite traiter comme globale. Dans chaque module qui en utilise, je n'utilise pas "from g import var", car cela ne donne qu'une variable locale initialisée à partir de g uniquement au moment de l'importation. Je fais la plupart des références sous la forme g.var, et le "g." me rappelle constamment que j’ai affaire à une variable potentiellement accessible à d’autres modules.

Si la valeur d'une telle variable globale doit être utilisée fréquemment dans une fonction d'un module, cette fonction peut alors créer une copie locale: var = g.var. Cependant, il est important de réaliser que les assignations à var sont locales et que g.var global ne peut pas être mis à jour sans référencer explicitement g.var dans une assignation.

Notez que vous pouvez également avoir plusieurs modules de ce type partagés par différents sous-ensembles de vos modules pour mieux contrôler les choses. La raison pour laquelle j'utilise des noms abrégés pour mes modules globals est d'éviter de trop encombrer le code avec des occurrences. Avec un peu d'expérience, ils deviennent suffisamment mnémoniques avec seulement 1 ou 2 caractères.

Il est toujours possible d’affecter g.x, par exemple, lorsque x n’a pas déjà été défini dans g, et un autre module peut alors accéder à g.x. Cependant, même si l'interprète le permet, cette approche n'est pas aussi transparente et je l'évite. Il est toujours possible de créer accidentellement une nouvelle variable dans g à la suite d’une faute de frappe dans le nom de la variable pour une affectation. Parfois, un examen de dir (g) est utile pour découvrir des noms inattendus qui pourraient être dus à un tel accident.

Vous pouvez passer les globales d'un module à un autre:

Dans le module A:

import module_b
my_var=2
module_b.do_something_with_my_globals(globals())
print my_var

Dans le module B:

def do_something_with_my_globals(glob): # glob is simply a dict.
    glob["my_var"]=3

Les variables globales sont généralement une mauvaise idée, mais vous pouvez le faire en attribuant à __ construit __ :

__builtins__.foo = 'something'
print foo

De plus, les modules eux-mêmes sont des variables auxquelles vous pouvez accéder à partir de n’importe quel module. Donc, si vous définissez un module appelé my_globals.py :

# my_globals.py
foo = 'something'

Vous pouvez également l'utiliser de n'importe où:

import my_globals
print my_globals.foo

Utiliser des modules plutôt que de modifier __ builtins __ est généralement une méthode plus simple pour effectuer des globals de ce type.

Vous pouvez déjà le faire avec des variables de niveau module. Les modules sont les mêmes quel que soit le module depuis lequel ils sont importés. Ainsi, vous pouvez faire de la variable une variable de niveau module dans le module de votre choix, puis y accéder ou l’affecter à partir d’autres modules. Il serait préférable d'appeler une fonction pour définir la valeur de la variable ou d'en faire une propriété d'un objet singleton. Ainsi, si vous devez exécuter du code lorsque la variable a été modifiée, vous pouvez le faire sans endommager l'interface externe de votre module.

Ce n’est généralement pas un excellent moyen de faire les choses & # 8212; l’utilisation de globals est rarement & # 8212; mais je pense que c'est la manière la plus propre de le faire.

Je voulais publier une réponse indiquant qu'il existe un cas où la variable ne sera pas trouvée.

Les importations cycliques peuvent perturber le comportement du module.

Par exemple:

premier.py

import second
var = 1

seconde.py

import first
print(first.var)  # will throw an error because the order of execution happens before var gets declared.

main.py

import first

Sur cet exemple, cela devrait être évident, mais dans une grande base de code, cela peut être très déroutant.

Cela ressemble à une modification de l’espace de nom __ construit __ . Pour le faire:

import __builtin__
__builtin__.foo = 'some-value'

N'utilisez pas le __ builtins __ directement (remarquez le "s" supplémentaire) - cela peut apparemment être un dictionnaire ou un module. Merci à & # 932; & # 918; & # 937; & # 932; & # 918; & # 921; & # 927; & # 933; pour le signaler, vous pouvez en trouver davantage ici .

Maintenant, toto est disponible pour être utilisé partout.

Je ne recommande pas de faire cela en général, mais le programmeur décide de l'utiliser.

L'affectation à cela doit être effectuée comme ci-dessus, le simple fait de définir foo = 'une autre valeur' ?? ne le définira que dans l'espace de nom actuel.

J'utilise ceci pour un couple de fonctions primitives intégrées qui me manquaient vraiment. Un exemple est une fonction de recherche qui a la même sémantique d’utilisation que filtre, mapper, réduire.

def builtin_find(f, x, d=None):
    for i in x:
        if f(i):
            return i
    return d

import __builtin__
__builtin__.find = builtin_find

Une fois que cela est exécuté (par exemple, en important près de votre point d’entrée), tous vos modules peuvent utiliser find () comme si, évidemment, il était intégré.

find(lambda i: i < 0, [1, 3, 0, -5, -10])  # Yields -5, the first negative.

Remarque: Vous pouvez le faire, bien sûr, avec un filtre et une autre ligne pour tester la longueur zéro, ou avec une réduction dans une sorte de ligne étrange, mais j'ai toujours pensé que c'était étrange.

Je pouvais obtenir des variables modifiables (ou mutables ) entre modules en utilisant un dictionnaire:

# in myapp.__init__
Timeouts = {} # cross-modules global mutable variables for testing purpose
Timeouts['WAIT_APP_UP_IN_SECONDS'] = 60

# in myapp.mod1
from myapp import Timeouts

def wait_app_up(project_name, port):
    # wait for app until Timeouts['WAIT_APP_UP_IN_SECONDS']
    # ...

# in myapp.test.test_mod1
from myapp import Timeouts

def test_wait_app_up_fail(self):
    timeout_bak = Timeouts['WAIT_APP_UP_IN_SECONDS']
    Timeouts['WAIT_APP_UP_IN_SECONDS'] = 3
    with self.assertRaises(hlp.TimeoutException) as cm:
        wait_app_up(PROJECT_NAME, PROJECT_PORT)
    self.assertEqual("Timeout while waiting for App to start", str(cm.exception))
    Timeouts['WAIT_JENKINS_UP_TIMEOUT_IN_SECONDS'] = timeout_bak

Lors du lancement de test_wait_app_up_fail , la durée du délai d'attente réel est de 3 secondes.

Je me suis demandé s'il serait possible d'éviter certains inconvénients de l'utilisation de variables globales (voir par exemple http: //wiki.c2.com/?GlobalVariablesAreBad ) en utilisant un espace de noms de classe plutôt qu'un espace de noms global / module pour transmettre des valeurs de variables. Le code suivant indique que les deux méthodes sont essentiellement identiques. L'utilisation des espaces de noms de classe présente un léger avantage, comme expliqué ci-dessous.

Les fragments de code suivants montrent également que des attributs ou des variables peuvent être créés et supprimés de manière dynamique dans les espaces de nom global / module et les espaces de nom de classe.

wall.py

# Note no definition of global variables

class router:
    """ Empty class """

J’appelle ce module 'wall' car il est utilisé pour renvoyer des variables hors de. Il servira d’espace pour définir temporairement les variables globales et les attributs de la classe vide 'routeur' à l’échelle de la classe.

source.py

import wall
def sourcefn():
    msg = 'Hello world!'
    wall.msg = msg
    wall.router.msg = msg

Ce module importe un mur et définit une seule fonction sourcefn qui définit un message et l’émet par deux mécanismes différents, l’un via les fonctions globales et l’autre via la fonction de routeur. Notez que les variables wall.msg et wall.router.message sont définies ici pour la première fois dans leurs espaces de noms respectifs.

dest.py

import wall
def destfn():

    if hasattr(wall, 'msg'):
        print 'global: ' + wall.msg
        del wall.msg
    else:
        print 'global: ' + 'no message'

    if hasattr(wall.router, 'msg'):
        print 'router: ' + wall.router.msg
        del wall.router.msg
    else:
        print 'router: ' + 'no message'

Ce module définit une fonction destfn qui utilise les deux mécanismes différents pour recevoir les messages émis par la source. Cela laisse à penser que la variable 'msg' peut ne pas exister. destfn supprime également les variables une fois affichées.

main.py

import source, dest

source.sourcefn()

dest.destfn() # variables deleted after this call
dest.destfn()

Ce module appelle les fonctions définies précédemment en séquence. Après le premier appel à dest.destfn , les variables wall.msg et wall.router.msg n'existent plus.

Le résultat du programme est:

global: Bonjour tout le monde!
routeur: Bonjour tout le monde!
global: pas de message
routeur: pas de message

Les fragments de code ci-dessus montrent que les mécanismes de variable module / global et classe / classe sont essentiellement identiques.

Si de nombreuses variables doivent être partagées, la pollution des espaces de noms peut être gérée à l'aide de plusieurs modules de type mur, par exemple. wall1, wall2 etc. ou en définissant plusieurs classes de type routeur dans un seul fichier. Ce dernier est légèrement plus ordonné, ce qui représente peut-être un avantage marginal pour l’utilisation du mécanisme de variable de classe.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top