Résolue

Accès à l'espace de nom local d'une fonction englobante

# Fonctions # Python

Est-ce qu'on peux accéder a l'espace de nom local de la fonction englobante ?
Dans l'exemple ci-dessous, est ce que Python me permet de récupérer l'espace local de func1, depuis func2 ?

def func1():
    a = 2
    def func2():
        print("Comment print le contenu de l'espace de nom local de func1 depuis func2 ?")
    func2()


func1()

Je me pose la question parce que si depuis func1 je peux peux print la variable a alors qu'elle n'est pas déclarée dans func2, c'est bien que Python à un mécanisme sous-jacent qui lui permet d'accéder à l'espace local de func1. Et j'aimerai savoir (par curiosité), si je peux le faire manuellement, et si oui, comment ?

Salut,

Je vois, tu ne peux pas le print directement. Je pensais qu'avec la variable __closure__ il y aurait moyen... :)

Sinon tu fait une copie de l'espace local et tu le récupères avec la closure dans la fonction 2 ahah

Ca fait 2 jours que je tourne et retourne les concepts de namespace, scope et closure dans tous les sens pour essayer d'y voir plus clair. C'est vraiment pas évident à comprendre mais je crois avoir pigé le truc. J'ai fait le petit bout de code suivant pour essayer de bien comprendre. Je l'avoue, ça ne sert strictement à rien de faire tout ça, mais c'est pour essayer de comprendre ce qui se passe sous le capot.

Tout ce que je vais écrire ci-dessous est à prendre avec pincettes, car c'est ma compréhension du sujet à l'instant T, et il est tout à fait possible que je me sois planté (je suis preneur de retours / conseils si jamais je raconte des bêtises).

1) Ma question initiale était : est-il possible depuis func2, d'afficher dynamiquement le contenu de l'espace local de func1.

Réponse : non ce n'est pas possible, parce que l'espace local de func1 a été détruit au moment ou la fonction a terminée son exécution.

2) De ce constat découle une seconde question : Comment est ce possible que func1 puisse lire le contenu de la variable b alors que l'espace local de func1 a été détruit ?

Réponse : Comme func2 est une fonction imbriquée dans func1, le mécanisme de closure se met en place et uniquement les variables de func1 étant référencée dans func2 vont être capturées dans la closure de func1. C'est notamment pour ça que la variable a serait accessible depuis func2 si jamais je rajoutais un print(a).

3) Du coup nouvelle question : est-ce que je peux dynamiquement afficher le contenu de tous mes objets stockés dans le scope de la closure de func2 depuis func2 ?
Réponse : Oui, comme le montre le code ci-dessous

def func1():
    a = 2
    b = 3
    c = "test"

    def func2():
        # seul a et c seront "sauvegardés" dans la closure de func2. Comme b n'est jamais référencé, il ne sera plus accessible
        nonlocal a
        _ = c

        # on créé dynamiquement un dictionnaire qui contiendra tous les objets de ma closure ainsi que leurs valeurs
        dict_var_closure = {}
        for index, var_name in enumerate(func2.__code__.co_freevars):
            dict_var_closure[var_name] = func2.__closure__[index].cell_contents
        print(dict_var_closure)

    return func2

func1()()

Ce code va me retourner : {'a': 2, 'c': 'test', 'func2': <function func1.<locals="">.func2 at 0x00000205886ADEE0>}

J'arrive donc bien à retrouver dynamiquement mes variables a et c. En revanche, b n'est plus accessible car elle n'est jamais utilisée dans func2.

Est-ce que les explications ci-dessous sont correctes ou est-ce que je me plante sur certains aspects ?

Gabriel Trouvé

Mentor

Dans l'ensemble tu as bien compris !

Pourquoi tu fais un nonlocal a d'ailleurs ?

Pour référencer la variable a dans func2. Si je n'avais pas fait ça, a n'aurait pas été capturée lors de la closure et je n'aurai pas pu y accéder dans mon dict_var_closure .

Gabriel Trouvé

Mentor

aah ok ^^

Même _ = a aurait suffit.

Mais très bien ce que tu fais .... :)

Inscris-toi

(c'est gratuit !)

Inscris-toi

Tu dois créer un compte pour participer aux discussions.

Créer un compte

Rechercher sur le site

Formulaire de contact

Inscris-toi à Docstring

Pour commencer ton apprentissage.

Tu as déjà un compte ? Connecte-toi.