Utilisation de variables globales dans une fonction

3116

Comment créer ou utiliser une variable globale dans une fonction?

Si je crée une variable globale dans une fonction, comment puis-je utiliser cette variable globale dans une autre fonction? Dois-je stocker la variable globale dans une variable locale de la fonction qui a besoin de son accès?

user46646
la source

Réponses:

4249

Vous pouvez utiliser une variable globale dans d'autres fonctions en la déclarant comme globaldans chaque fonction qui lui est affectée:

globvar = 0

def set_globvar_to_one():
    global globvar    # Needed to modify global copy of globvar
    globvar = 1

def print_globvar():
    print(globvar)     # No need for global declaration to read value of globvar

set_globvar_to_one()
print_globvar()       # Prints 1

J'imagine que la raison en est que, puisque les variables globales sont si dangereuses, Python veut s'assurer que vous savez vraiment que c'est ce que vous jouez en exigeant explicitement le globalmot - clé.

Consultez les autres réponses si vous souhaitez partager une variable globale entre les modules.

Paul Stephenson
la source
839
Il est extrêmement exagéré de qualifier les mondiaux de «si dangereux». Les globaux sont parfaitement bien dans toutes les langues qui ont jamais existé et qui existeront toujours. Ils ont leur place. Ce que vous auriez dû dire, c'est qu'ils peuvent causer des problèmes si vous ne savez pas comment programmer.
Anthony
208
Je pense qu'ils sont assez dangereux. Cependant, en python, les variables "globales" sont en fait au niveau du module, ce qui résout beaucoup de problèmes.
Fábio Santos
247
Je ne suis pas d'accord que la raison pour laquelle Python nécessite le globalmot-clé est que les globaux sont dangereux. C'est plutôt parce que le langage ne vous oblige pas à déclarer explicitement des variables et suppose automatiquement qu'une variable que vous affectez a une portée de fonction, sauf indication contraire. Le globalmot-clé est le moyen qui est fourni pour le dire autrement.
Nate CK
7
@avgvstvs: Et si vous implémentez le même programme sans globaux, vous avez toujours le même nombre de chemins de code. L'argument que vous avez avancé n'est pas contre les mondiaux.
Courses de légèreté en orbite
13
@LightnessRacesinOrbit Je ne comprends pas votre point. Si vous supprimez une variable globale, vous supprimez le facteur de complication en ce que maintenant, les fonctions arbitraires ne peuvent plus modifier l'état du programme , à différents points de l'exécution - modifiant ainsi l'exécution d'une manière qui est autrement imperceptible pour les autres fonctions qui dépendent de cette variable. Vous n'avez plus à garder la trace de: "Un f2()changement d'état f3()peut-il faire quelque chose d'inattendu maintenant? Les fonctions peuvent maintenant fonctionner indépendamment de l'état du programme externe.
avgvstvs
775

Si je comprends bien votre situation, ce que vous voyez est le résultat de la façon dont Python gère les espaces de noms locaux (fonction) et globaux (module).

Disons que vous avez un module comme celui-ci:

# sample.py
myGlobal = 5

def func1():
    myGlobal = 42

def func2():
    print myGlobal

func1()
func2()

Vous pouvez vous attendre à ce que cela imprime 42, mais à la place, il imprime 5. Comme cela a déjà été mentionné, si vous ajoutez une globaldéclaration ' ' à func1(), alors func2()imprimera 42.

def func1():
    global myGlobal
    myGlobal = 42

Ce qui se passe ici, c'est que Python suppose que tout nom attribué à , n'importe où dans une fonction, est local à cette fonction, sauf indication contraire explicite. S'il ne lit qu'à partir d'un nom et que le nom n'existe pas localement, il essaiera de rechercher le nom dans toutes les étendues contenant (par exemple la portée globale du module).

Par myGlobalconséquent, lorsque vous attribuez 42 au nom , Python crée une variable locale qui associe la variable globale du même nom. Ce local sort du cadre et est récupéré lors du func1()retour; en attendant, func2()ne peut jamais voir autre chose que le nom global (non modifié). Notez que cette décision d'espace de noms se produit au moment de la compilation, pas au moment de l'exécution - si vous deviez lire la valeur de myGlobalinside func1()avant de l'affecter, vous obtiendriez un UnboundLocalError, car Python a déjà décidé que ce devait être une variable locale mais elle n'a pas encore eu de valeur associée. Mais en utilisant l' globalinstruction ' ', vous dites à Python qu'il doit chercher ailleurs le nom au lieu de lui attribuer localement.

(Je crois que ce comportement provient en grande partie d'une optimisation des espaces de noms locaux - sans ce comportement, la machine virtuelle de Python devrait effectuer au moins trois recherches de nom chaque fois qu'un nouveau nom est attribué à l'intérieur d'une fonction (pour garantir que le nom ne l'a pas fait) existent déjà au niveau module / intégré), ce qui ralentirait considérablement une opération très courante.)

Jeff Shannon
la source
Vous avez mentionné que la décision relative à l'espace de noms se produit au moment de la compilation , je ne pense pas que ce soit vrai. d'après ce que j'apprends, la compilation de python ne vérifie que les erreurs de syntaxe, pas l'erreur de nom, essayez cet exemple def A (): x + = 1 , si vous ne l'exécutez pas, il ne donnera pas UnboundLocalError , veuillez vérifier merci
watashiSHUN
1
Il est courant d'utiliser une lettre majuscule pour les variables globales commeMyGlobal = 5
Vassilis
3
@watashiSHUN: La décision de l' espace de noms ne se produisent lors de la compilation. Décider que xc'est local est différent de vérifier au moment de l'exécution si le nom local était lié à une valeur avant d'être utilisé la première fois.
BlackJack
9
@Vassilis: Il est commun en majuscules toutes les lettres: MY_GLOBAL = 5. Voir le Guide de style pour le code Python .
BlackJack
223

Vous voudrez peut-être explorer la notion d' espaces de noms . En Python, le module est le lieu naturel pour les données globales :

Chaque module possède sa propre table de symboles privée, qui est utilisée comme table de symboles globale par toutes les fonctions définies dans le module. Ainsi, l'auteur d'un module peut utiliser des variables globales dans le module sans se soucier des conflits accidentels avec les variables globales d'un utilisateur. D'un autre côté, si vous savez ce que vous faites, vous pouvez toucher les variables globales d'un module avec la même notation utilisée pour faire référence à ses fonctions modname.itemname,.

Une utilisation spécifique de global-in-a-module est décrite ici - Comment partager des variables globales entre modules? , et pour être complet, le contenu est partagé ici:

La manière canonique de partager des informations entre les modules d'un même programme consiste à créer un module de configuration spécial (souvent appelé config ou cfg ). Importez simplement le module de configuration dans tous les modules de votre application; le module devient alors disponible en tant que nom global. Puisqu'il n'y a qu'une seule instance de chaque module, toutes les modifications apportées à l'objet module sont reflétées partout. Par exemple:

Fichier: config.py

x = 0   # Default value of the 'x' configuration setting

Fichier: mod.py

import config
config.x = 1

Fichier: main.py

import config
import mod
print config.x
gimel
la source
1
pour une raison que je n'aime pas config.x puis-je m'en débarrasser? Je suis venu avec x = lambda: config.xet j'ai ensuite la nouvelle valeur x(). pour une raison quelconque, l'avoir a = config.xne fait pas l'affaire pour moi.
vladosaurus
3
@vladosaurus from config import xrésout-il cela?
jhylands
93

Python utilise une heuristique simple pour décider de l'étendue à partir de laquelle il doit charger une variable, entre local et global. Si un nom de variable apparaît sur le côté gauche d'une affectation, mais n'est pas déclaré global, il est supposé être local. S'il n'apparaît pas sur le côté gauche d'une affectation, il est supposé être global.

>>> import dis
>>> def foo():
...     global bar
...     baz = 5
...     print bar
...     print baz
...     print quux
... 
>>> dis.disassemble(foo.func_code)
  3           0 LOAD_CONST               1 (5)
              3 STORE_FAST               0 (baz)

  4           6 LOAD_GLOBAL              0 (bar)
              9 PRINT_ITEM          
             10 PRINT_NEWLINE       

  5          11 LOAD_FAST                0 (baz)
             14 PRINT_ITEM          
             15 PRINT_NEWLINE       

  6          16 LOAD_GLOBAL              1 (quux)
             19 PRINT_ITEM          
             20 PRINT_NEWLINE       
             21 LOAD_CONST               0 (None)
             24 RETURN_VALUE        
>>> 

Voyez comment baz, qui apparaît sur le côté gauche d'une affectation dans foo(), est la seule LOAD_FASTvariable.

SingleNegationElimination
la source
12
L'heuristique recherche les opérations de liaison . L'affectation est une de ces opérations, en important une autre. Mais la cible d'une forboucle et le nom après les instructions asin withet exceptsont également liés à.
Martijn Pieters
@MartijnPieters Pour le nom après asdans une exceptclause, ce n'était pas évident pour moi. Mais il est automatiquement supprimé pour économiser de la mémoire.
Robert
1
@Robert: non pas pour économiser de la mémoire, mais pour éviter de créer une référence circulaire, ce qui peut entraîner des fuites de mémoire. En effet, une exception fait référence à une traceback et la traceback fait référence à chaque espace de noms local et global le long de la pile d'appels entière, y compris la as ...cible dans le gestionnaire d'exceptions.
Martijn Pieters
62

Si vous souhaitez faire référence à une variable globale dans une fonction, vous pouvez utiliser le mot clé global pour déclarer quelles variables sont globales. Vous n'êtes pas obligé de l'utiliser dans tous les cas (comme quelqu'un le prétend ici à tort) - si le nom référencé dans une expression ne peut pas être trouvé dans la portée locale ou les portées dans les fonctions dans lesquelles cette fonction est définie, il est recherché parmi les globaux variables.

Cependant, si vous attribuez à une nouvelle variable non déclarée comme globale dans la fonction, elle est implicitement déclarée comme locale, et elle peut occulter toute variable globale existante avec le même nom.

En outre, les variables globales sont utiles, contrairement à certains fanatiques de POO qui prétendent le contraire - en particulier pour les petits scripts, où la POO est exagérée.

JS
la source
Absolument re. fanatiques. La plupart des utilisateurs de Python l'utilisent pour les scripts et créent de petites fonctions pour séparer les petits morceaux de code.
Paul Uszak
51

Si je crée une variable globale dans une fonction, comment puis-je utiliser cette variable dans une autre fonction?

Nous pouvons créer un global avec la fonction suivante:

def create_global_variable():
    global global_variable # must declare it to be a global first
    # modifications are thus reflected on the module's global scope
    global_variable = 'Foo' 

L'écriture d'une fonction n'exécute pas réellement son code. Nous appelons donc la create_global_variablefonction:

>>> create_global_variable()

Utiliser des globaux sans modification

Vous pouvez simplement l'utiliser, tant que vous ne vous attendez pas à changer vers quel objet il pointe:

Par exemple,

def use_global_variable():
    return global_variable + '!!!'

et maintenant nous pouvons utiliser la variable globale:

>>> use_global_variable()
'Foo!!!'

Modification de la variable globale depuis l'intérieur d'une fonction

Pour pointer la variable globale vers un autre objet, vous devez réutiliser le mot clé global:

def change_global_variable():
    global global_variable
    global_variable = 'Bar'

Notez qu'après avoir écrit cette fonction, le code qui la modifie n'a toujours pas été exécuté:

>>> use_global_variable()
'Foo!!!'

Donc, après avoir appelé la fonction:

>>> change_global_variable()

nous pouvons voir que la variable globale a été modifiée. Le global_variablenom pointe désormais sur 'Bar':

>>> use_global_variable()
'Bar!!!'

Notez que "global" en Python n'est pas vraiment global - c'est seulement global au niveau du module. Il n'est donc disponible que pour les fonctions écrites dans les modules dans lesquels il est global. Les fonctions se souviennent du module dans lequel elles sont écrites, donc lorsqu'elles sont exportées dans d'autres modules, elles regardent toujours dans le module dans lequel elles ont été créées pour trouver des variables globales.

Variables locales du même nom

Si vous créez une variable locale du même nom, elle éclipsera une variable globale:

def use_local_with_same_name_as_global():
    # bad name for a local variable, though.
    global_variable = 'Baz' 
    return global_variable + '!!!'

>>> use_local_with_same_name_as_global()
'Baz!!!'

Mais l'utilisation de cette variable locale mal nommée ne change pas la variable globale:

>>> use_global_variable()
'Bar!!!'

Notez que vous devez éviter d'utiliser les variables locales avec les mêmes noms que les globales, sauf si vous savez précisément ce que vous faites et que vous avez une très bonne raison de le faire. Je n'ai pas encore rencontré une telle raison.

On obtient le même comportement en classe

Un commentaire de suivi demande:

que faire si je veux créer une variable globale à l'intérieur d'une fonction à l'intérieur d'une classe et que je veux utiliser cette variable à l'intérieur d'une autre fonction à l'intérieur d'une autre classe?

Ici, je démontre que nous obtenons le même comportement dans les méthodes que dans les fonctions régulières:

class Foo:
    def foo(self):
        global global_variable
        global_variable = 'Foo'

class Bar:
    def bar(self):
        return global_variable + '!!!'

Foo().foo()

Et maintenant:

>>> Bar().bar()
'Foo!!!'

Mais je suggère qu'au lieu d'utiliser des variables globales, vous utilisez des attributs de classe, pour éviter d'encombrer l'espace de noms du module. Notez également que nous n'utilisons pas d' selfarguments ici - il peut s'agir de méthodes de classe (pratiques si la mutation de l'attribut de classe de l' clsargument habituel ) ou de méthodes statiques (non selfou cls).

Aaron Hall
la source
Cool, mais que faire si je veux créer une variable globale à l'intérieur d'une fonction à l'intérieur d'une classe et que je veux utiliser cette variable à l'intérieur d'une autre fonction à l'intérieur d'une autre classe? Un peu coincé ici
anonmanx
2
@anonmanx Je ne sais pas pourquoi vous êtes coincé, c'est le même comportement dans une méthode que dans une fonction régulière. Mais je mettrai à jour ma réponse avec votre remarque et un code de démonstration, d'accord?
Aaron Hall
1
@anonmanx comment ça?
Aaron Hall
OK, j'ai compris. Je vais donc devoir appeler explicitement cette fonction pour utiliser cette variable globale.
anonmanx
47

En plus des réponses déjà existantes et pour rendre cela plus confus:

En Python, les variables qui ne sont référencées qu'à l'intérieur d'une fonction sont implicitement globales . Si une variable se voit attribuer une nouvelle valeur n'importe où dans le corps de la fonction, elle est supposée être locale . Si une variable reçoit une nouvelle valeur à l'intérieur de la fonction, la variable est implicitement locale et vous devez la déclarer explicitement comme «globale».

Bien qu'un peu surprenant au début, un moment de réflexion explique cela. D'une part, l'exigence de global pour les variables affectées fournit une barre contre les effets secondaires imprévus. D'un autre côté, si global était requis pour toutes les références globales, vous utiliseriez global tout le temps. Vous devez déclarer comme globale chaque référence à une fonction intégrée ou à un composant d'un module importé. Cet encombrement irait à l'encontre de l'utilité de la déclaration mondiale pour identifier les effets secondaires.

Source: Quelles sont les règles pour les variables locales et globales en Python? .

Rauni Lillemets
la source
34

Avec une exécution parallèle, les variables globales peuvent provoquer des résultats inattendus si vous ne comprenez pas ce qui se passe. Voici un exemple d'utilisation d'une variable globale dans le cadre du multitraitement. Nous pouvons clairement voir que chaque processus fonctionne avec sa propre copie de la variable:

import multiprocessing
import os
import random
import sys
import time

def worker(new_value):
    old_value = get_value()
    set_value(random.randint(1, 99))
    print('pid=[{pid}] '
          'old_value=[{old_value:2}] '
          'new_value=[{new_value:2}] '
          'get_value=[{get_value:2}]'.format(
          pid=str(os.getpid()),
          old_value=old_value,
          new_value=new_value,
          get_value=get_value()))

def get_value():
    global global_variable
    return global_variable

def set_value(new_value):
    global global_variable
    global_variable = new_value

global_variable = -1

print('before set_value(), get_value() = [%s]' % get_value())
set_value(new_value=-2)
print('after  set_value(), get_value() = [%s]' % get_value())

processPool = multiprocessing.Pool(processes=5)
processPool.map(func=worker, iterable=range(15))

Production:

before set_value(), get_value() = [-1]
after  set_value(), get_value() = [-2]
pid=[53970] old_value=[-2] new_value=[ 0] get_value=[23]
pid=[53971] old_value=[-2] new_value=[ 1] get_value=[42]
pid=[53970] old_value=[23] new_value=[ 4] get_value=[50]
pid=[53970] old_value=[50] new_value=[ 6] get_value=[14]
pid=[53971] old_value=[42] new_value=[ 5] get_value=[31]
pid=[53972] old_value=[-2] new_value=[ 2] get_value=[44]
pid=[53973] old_value=[-2] new_value=[ 3] get_value=[94]
pid=[53970] old_value=[14] new_value=[ 7] get_value=[21]
pid=[53971] old_value=[31] new_value=[ 8] get_value=[34]
pid=[53972] old_value=[44] new_value=[ 9] get_value=[59]
pid=[53973] old_value=[94] new_value=[10] get_value=[87]
pid=[53970] old_value=[21] new_value=[11] get_value=[21]
pid=[53971] old_value=[34] new_value=[12] get_value=[82]
pid=[53972] old_value=[59] new_value=[13] get_value=[ 4]
pid=[53973] old_value=[87] new_value=[14] get_value=[70]
Bohdan
la source
25

Ce que vous dites, c'est d'utiliser la méthode comme ceci:

globvar = 5

def f():
    var = globvar
    print(var)

f()  # Prints 5

Mais la meilleure façon est d'utiliser la variable globale comme ceci:

globavar = 5
def f():
    global globvar
    print(globvar)
f()   #prints 5

Les deux donnent la même sortie.

gxyd
la source
25

Il s'avère que la réponse est toujours simple.

Voici un petit exemple de module avec un moyen simple de l'afficher dans une maindéfinition:

def five(enterAnumber,sumation):
    global helper
    helper  = enterAnumber + sumation

def isTheNumber():
    return helper

Voici comment l'afficher dans une maindéfinition:

import TestPy

def main():
    atest  = TestPy
    atest.five(5,8)
    print(atest.isTheNumber())

if __name__ == '__main__':
    main()

Ce code simple fonctionne comme ça, et il s'exécutera. J'espère que ça aide.

user2876408
la source
1
merci, je suis nouveau sur python, mais je connais un peu le java. ce que vous avez dit a fonctionné pour moi. et écrire global a <ENTER> dans la classe .. semble plus logique pour moi que dans une fonction écrivant 'global a' .. Je remarque que vous ne pouvez pas dire global a = 4
barlop
2
C'est probablement l'astuce python la plus simple mais très utile pour moi. Je nomme ce module global_varset initialise les données dans init_global_varscelui qui est appelé dans le script de démarrage. Ensuite, je crée simplement une méthode d'accesseur pour chaque var globale définie. J'espère pouvoir voter à plusieurs reprises! Merci Peter!
swdev
1
Que se passe-t-il s'il y a beaucoup de variables globales et que je ne veux pas les énumérer une par une après une instruction globale?
jtlz2
23

Vous devez référencer la variable globale dans chaque fonction que vous souhaitez utiliser.

Comme suit:

var = "test"

def printGlobalText():
    global var #wWe are telling to explicitly use the global version
    var = "global from printGlobalText fun."
    print "var from printGlobalText: " + var

def printLocalText():
    #We are NOT telling to explicitly use the global version, so we are creating a local variable
    var = "local version from printLocalText fun"
    print "var from printLocalText: " + var

printGlobalText()
printLocalText()
"""
Output Result:
var from printGlobalText: global from printGlobalText fun.
var from printLocalText: local version from printLocalText
[Finished in 0.1s]
"""
Mohamed El-Saka
la source
3
'dans chaque fonction que vous souhaitez utiliser' est subtilement incorrect, devrait être plus proche de: 'dans chaque fonction où vous souhaitez mettre à jour '
spazm
21

Vous ne stockez pas réellement le global dans une variable locale, vous créez simplement une référence locale au même objet auquel votre référence globale d'origine fait référence. N'oubliez pas que presque tout en Python est un nom faisant référence à un objet, et rien n'est copié en fonctionnement habituel.

Si vous n'aviez pas à spécifier explicitement quand un identifiant devait se référer à un global prédéfini, alors vous auriez probablement à spécifier explicitement quand un identifiant est une nouvelle variable locale à la place (par exemple, avec quelque chose comme la commande 'var' vu en JavaScript). Étant donné que les variables locales sont plus courantes que les variables globales dans tout système sérieux et non trivial, le système de Python a plus de sens dans la plupart des cas.

Vous pourriez avoir un langage qui tenterait de deviner, en utilisant une variable globale si elle existait ou en créant une variable locale si ce n'était pas le cas. Cependant, ce serait très sujet aux erreurs. Par exemple, l'importation d'un autre module pourrait introduire par inadvertance une variable globale de ce nom, modifiant le comportement de votre programme.

Kylotan
la source
17

Essaye ça:

def x1():
    global x
    x = 6

def x2():
    global x
    x = x+1
    print x

x = 5
x1()
x2()  # output --> 7
Sagar Mehta
la source
15

Si vous avez une variable locale du même nom, vous pouvez utiliser la globals()fonction .

globals()['your_global_var'] = 42
Martin Thoma
la source
14

Après et en tant qu'add-on, utilisez un fichier pour contenir toutes les variables globales toutes déclarées localement, puis import as:

Fichier initval.py :

Stocksin = 300
Prices = []

Fichier getstocks.py :

import initval as iv

def getmystocks(): 
    iv.Stocksin = getstockcount()


def getmycharts():
    for ic in range(iv.Stocksin):
Georgy
la source
1
Quel est l'avantage de déplacer les variables globales vers un autre fichier? Est-ce juste pour regrouper les variables globales dans un petit fichier? Et pourquoi utiliser la déclaration import ... as ...? Pourquoi pas juste import ...?
olibre
1
Ah ... J'ai enfin compris l'avantage: pas besoin d'utiliser le mot-clé global:-) => +1 :-) Merci de modifier votre réponse pour clarifier ces interrogations que d'autres personnes peuvent également avoir. Vive
olibre
13

L'écriture dans des éléments explicites d'un tableau global n'a apparemment pas besoin de la déclaration globale, bien que l'écriture "en gros" ait cette exigence:

import numpy as np

hostValue = 3.14159
hostArray = np.array([2., 3.])
hostMatrix = np.array([[1.0, 0.0],[ 0.0, 1.0]])

def func1():
    global hostValue    # mandatory, else local.
    hostValue = 2.0

def func2():
    global hostValue    # mandatory, else UnboundLocalError.
    hostValue += 1.0

def func3():
    global hostArray    # mandatory, else local.
    hostArray = np.array([14., 15.])

def func4():            # no need for globals
    hostArray[0] = 123.4

def func5():            # no need for globals
    hostArray[1] += 1.0

def func6():            # no need for globals
    hostMatrix[1][1] = 12.

def func7():            # no need for globals
    hostMatrix[0][0] += 0.33

func1()
print "After func1(), hostValue = ", hostValue
func2()
print "After func2(), hostValue = ", hostValue
func3()
print "After func3(), hostArray = ", hostArray
func4()
print "After func4(), hostArray = ", hostArray
func5()
print "After func5(), hostArray = ", hostArray
func6()
print "After func6(), hostMatrix = \n", hostMatrix
func7()
print "After func7(), hostMatrix = \n", hostMatrix
Mike Lampton
la source
7

J'ajoute cela car je ne l'ai vu dans aucune des autres réponses et cela pourrait être utile pour quelqu'un aux prises avec quelque chose de similaire. La globals()fonction renvoie un dictionnaire de symboles globaux mutable où vous pouvez "magiquement" rendre les données disponibles pour le reste de votre code. Par exemple:

from pickle import load
def loaditem(name):
    with open(r"C:\pickle\file\location"+"\{}.dat".format(name), "rb") as openfile:
        globals()[name] = load(openfile)
    return True

et

from pickle import dump
def dumpfile(name):
    with open(name+".dat", "wb") as outfile:
        dump(globals()[name], outfile)
    return True

Vous permettra simplement de vider / charger des variables hors et dans l'espace de noms global. Super pratique, pas de bruit, pas de chichi. Je suis sûr que ce n'est que Python 3.

Rafaël Dera
la source
3
globals()renvoie toujours les globaux disponibles dans le contexte local, donc une mutation ici peut ne pas se refléter dans un autre module.
Kiran Jonnalagadda
6

Référencez l'espace de noms de classe où vous souhaitez que la modification apparaisse.

Dans cet exemple, le coureur utilise max à partir de la configuration du fichier. Je veux que mon test change la valeur de max lorsque le coureur l'utilise.

main / config.py

max = 15000

main / runner.py

from main import config
def check_threads():
    return max < thread_count 

tests / runner_test.py

from main import runner                # <----- 1. add file
from main.runner import check_threads
class RunnerTest(unittest):
   def test_threads(self):
       runner.max = 0                  # <----- 2. set global 
       check_threads()
llewellyn falco
la source
1

Les globaux vont bien - sauf avec le multitraitement

Les globaux liés au multitraitement sur différentes plates-formes / environnements, comme Windows / Mac OS d'un côté et Linux de l'autre, sont gênants.

Je vais vous montrer cela avec un exemple simple soulignant un problème que j'ai rencontré il y a quelque temps.

Si vous voulez comprendre pourquoi les choses sont différentes sous Windows / MacOs et Linux, vous devez savoir cela, le mécanisme par défaut pour démarrer un nouveau processus sur ...

  • Windows / MacOs est «apparition»
  • Linux est «fork»

Ils sont différents dans l'allocation de mémoire et l'initialisation ... (mais je n'entre pas dans le détail ici).

Jetons un œil au problème / exemple ...

import multiprocessing

counter = 0

def do(task_id):
    global counter
    counter +=1
    print(f'task {task_id}: counter = {counter}')

if __name__ == '__main__':

    pool = multiprocessing.Pool(processes=4)
    task_ids = list(range(4))
    pool.map(do, task_ids)

les fenêtres

Si vous exécutez cela sur Windows (et je suppose aussi sur MacOS), vous obtenez la sortie suivante ...

task 0: counter = 1
task 1: counter = 2
task 2: counter = 3
task 3: counter = 4

Linux

Si vous exécutez ceci sur Linux, vous obtenez à la place ce qui suit.

task 0: counter = 1
task 1: counter = 1
task 2: counter = 1
task 3: counter = 1
Thomas
la source