web-dev-qa-db-fra.com

Raison de globals () en Python?

Quelle est la raison d'avoir la fonction globals () en Python? Il ne retourne qu'un dictionnaire de variables globales, qui sont déjà globales, afin qu'elles puissent être utilisées n'importe où ... Je ne demande que par curiosité, en essayant d'apprendre le python.

def F():
    global x
    x = 1

def G():
    print(globals()["x"]) #will return value of global 'x', which is 1

def H():
    print(x) #will also return value of global 'x', which, also, is 1

F()
G()
H()

Je ne peux pas vraiment voir le point ici? Si j'avais des variables locales et globales, avec le même nom pour les deux, j'en aurais seulement besoin

def F():
    global x
    x = 1

def G():
    x = 5
    print(x) #5
    print(globals()["x"]) #1

F()
G()

Mais vous ne devriez jamais avoir le problème d'avoir deux variables portant le même nom et de devoir les utiliser toutes les deux dans la même portée.

58
user1632861

Python offre au programmeur un grand nombre d'outils pour l'introspection de l'environnement en cours d'exécution. globals() en est un exemple, et il peut être très utile dans une session de débogage de voir quels objets la portée globale contient réellement.

Je suis sûr que la logique qui la sous-tend est identique à celle d'utiliser locals() pour afficher les variables définies dans une fonction ou d'utiliser dir pour afficher le contenu d'un module ou les attributs d'un objet.

Venant d’un arrière-plan C++, je peux comprendre que ces choses semblent inutiles. Dans un environnement statiquement lié et typé, ils le seraient absolument. Dans ce cas, on sait exactement au moment de la compilation quelles variables sont globales et quels membres auront un objet, et même quels noms sont exportés par une autre unité de compilation.

Dans un langage dynamique, cependant, ces choses ne sont pas fixes; ils peuvent changer en fonction de la manière dont le code est importé, ou même pendant l'exécution. Pour cette raison au moins, avoir accès à ce type d'informations dans un débogueur peut s'avérer inestimable.

77
Ian Clelland

C'est également utile lorsque vous devez appeler une fonction à l'aide du nom de chaîne de la fonction. Par exemple:

def foo():
    pass

function_name_as_string = 'foo'

globals()[function_name_as_string]() # foo(). 
34
Alex Soroka

Vous pouvez transmettre le résultat de globals() et locals() aux commandes eval, execfile et __import__. Cela crée un environnement restreint pour ces commandes. 

Ainsi, ces fonctions existent pour prendre en charge d’autres fonctions qui bénéficient d’un environnement potentiellement différent du contexte actuel. Vous pouvez, par exemple, appeler globals() puis supprimer ou ajouter des variables avant d'appeler l'une de ces fonctions. 

8
Bryan Oakley

globals() est utile pour eval() - si vous souhaitez évaluer du code faisant référence à des variables dans la portée, ces variables seront soit globales, soit locales.


Pour développer un bit, la fonction intégrée eval() interprétera une chaîne de code Python qui lui est donnée. La signature est: eval(codeString, globals, locals), et vous l'utiliseriez comme suit:

def foo():
    x = 2
    y = eval("x + 1", globals(), locals())
    print("y=" + y) # should be 3

Cela fonctionne car l'interpréteur obtient la valeur x à partir du locals() dict de variables. Vous pouvez bien sûr fournir votre propre dict de variables à eval.

6
Richard Close

Cela peut être utile dans 'python déclaratif'. Par exemple, ci-dessous, FooDef et BarDef sont des classes utilisées pour définir une série de structures de données qui sont ensuite utilisées par un package en tant qu'entrée ou configuration. Cela vous donne beaucoup de flexibilité dans votre entrée, et vous n'avez pas besoin d'écrire un analyseur.

# FooDef, BarDef are classes

Foo_one = FooDef("This one", opt1 = False, valence = 3 )
Foo_two = FooDef("The other one", valence = 6, parent = Foo_one )

namelist = []
for i in range(6):
    namelist.append("nm%03d"%i)

Foo_other = FooDef("a third one", string_list = namelist )

Bar_thing = BarDef( (Foo_one, Foo_two), method = 'depth-first')

Notez que ce fichier de configuration utilise une boucle pour créer une liste de noms qui font partie de la configuration de Foo_other. Ainsi, ce langage de configuration est livré avec un «préprocesseur» très puissant, avec une bibliothèque d'exécution disponible. Si vous voulez, par exemple, trouver un journal complexe, ou extraire des éléments d’un fichier Zip et les décoder en base64, dans le cadre de la génération de votre configuration (cette approche n’est bien entendu pas recommandée, dans les cas où l’entrée peut provenir d’un fichier source non fiable ...)

Le paquet lit la configuration en utilisant quelque chose comme ce qui suit:

conf_globals = {}  # make a namespace
# Give the config file the classes it needs
conf_globals['FooDef']= mypkgconfig.FooDef  # both of these are based ...
conf_globals['BarDef']= mypkgconfig.BarDef  # ... on .DefBase

fname = "user.conf"
try:
    exec open(fname) in conf_globals
except Exception:
    ...as needed...
# now find all the definitions in there
# (I'm assuming the names they are defined with are
# significant to interpreting the data; so they
# are stored under those keys here).

defs = {}
for nm,val in conf_globals.items():
    if isinstance(val,mypkgconfig.DefBase):
        defs[nm] = val

Donc, pour en venir enfin au fait, globals() est utile, lorsque vous utilisez un tel package, si vous souhaitez créer une série de définitions de manière procédurale:

for idx in range(20):
    varname = "Foo_%02d" % i
    globals()[varname]= FooDef("one of several", id_code = i+1, scale_ratio = 2**i)

Cela équivaut à écrire

Foo_00 = FooDef("one of several", id_code = 1, scale_ratio=1)
Foo_01 = FooDef("one of several", id_code = 2, scale_ratio=2)
Foo_02 = FooDef("one of several", id_code = 3, scale_ratio=4)
... 17 more ...

PLY (Python-Lex-yacc) http://www.dabeaz.com/ply/ - Dans ce cas, PLY (Python-Lex-yacc) rassemble un ensemble de définitions à partir d'un module python. Les objets sont principalement des objets de fonction, mais les métadonnées des objets de fonction (leurs noms, leurs chaînes de documentation et leur ordre de définition) font également partie de l'entrée. Ce n'est pas un si bon exemple d'utilisation de globals(). En outre, il est importé par la "configuration" - cette dernière étant un script Python normal - et non l'inverse.

J'ai utilisé 'python déclaratif' sur quelques projets sur lesquels j'ai travaillé et j'ai eu l'occasion d'utiliser globals() lors de l'écriture de configurations pour ceux-ci. Vous pourriez certainement affirmer que cela était dû à une faiblesse dans la conception du 'langage' de la configuration. L'utilisation de globals() de cette manière ne produit pas de résultats très clairs; juste des résultats qu'il serait peut-être plus facile de maintenir que d'écrire une douzaine d'énoncés presque identiques.

Vous pouvez également l'utiliser pour donner une signification aux variables dans le fichier de configuration, en fonction de leurs noms:

# All variables above here starting with Foo_k_ are collected
# in Bar_klist
#
foo_k = [ v for k,v in globals().items() if k.startswith('Foo_k_')]
Bar_klist  = BarDef( foo_k , method = "kset")

Cette méthode peut s'avérer utile pour les modules any python qui définissent un grand nombre de tables et de structures afin de faciliter l'ajout d'éléments aux données, sans avoir à gérer également les références.

0
greggo

Il peut également être utilisé pour obtenir une instance de la classe 'classname' à partir d'une chaîne :

class C:
    def __init__(self, x):
        self.x = x
        print('Added new instance, x:', self.x)


def call(str):
    obj = globals()[str](4)
    return obj

c = call('C')
print(c.x)
0
Bart