web-dev-qa-db-fra.com

`del` sur un paquet a une sorte de mémoire

del semble avoir une certaine mémoire qui me laisse perplexe. Voir ce qui suit:

In [1]: import math

In [2]: math.cos(0)
Out[2]: 1.0

In [3]: del math.cos

In [4]: math.cos(0)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-4-9cdcc157d079> in <module>()
----> 1 math.cos(0)

AttributeError: module 'math' has no attribute 'cos'

Bien. Voyons ce qui se passe si nous supprimons l'ensemble du package mathématique:

In [5]: del math

In [6]: math.cos(0)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-6-9cdcc157d079> in <module>()
----> 1 math.cos(0)

NameError: name 'math' is not defined

Alors maintenant, les mathématiques ont disparu, comme prévu.

Maintenant, importons à nouveau les mathématiques:

In [7]: import math

In [8]: math.cos(0)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-8-9cdcc157d079> in <module>()
----> 1 math.cos(0)

AttributeError: module 'math' has no attribute 'cos'

Donc, en quelque sorte interactif python se souvient que math.cos a été supprimé spécifiquement même après que nous ayons supprimé le package mathématique entier et l'avons à nouveau importé.

Où python conserve-t-il ces connaissances? Peut-on y accéder? Peut-on le changer?

43
Aguy

Je dirais que le paquet est toujours considéré comme importé. Donc performant import math redéclare simplement le nom, mais avec l'ancien contenu.

Vous pouvez utiliser reload pour vous assurer que votre module est à nouveau entier, sauf que certaines versions de python nécessitent de supprimer l'entrée dans sys.modules également, ce qui rend l'utilisation de reload redondante:

import math
del math.cos
del math
sys.modules.pop("math")   # remove from loaded modules
import math
print(math.cos(0))  # 1.0

(cette différence entre les différentes versions de python, reload et import est discutée dans une question de suivi: si importlib.reload restaure un fichier supprimé) attribut dans Python 3.6? )

23
Jean-François Fabre

Un package n'est lu qu'une seule fois sur le disque, puis stocké en mémoire en tant que singleton mutable. La deuxième fois que vous l'importez, vous obtenez exactement le même singleton que vous avez précédemment importé, et il lui manque toujours son cos. del math supprime simplement le nom local pour celui-ci, il "n'importe pas" le paquet de Python globalement.

62
deceze

del math ne supprime pas du tout le paquet, il supprime simplement nom localmath dans le module actuel.

Comme tout autre objet, si d'autres références au module mathématique existent quelque part, il est conservé en mémoire.

Et en particulier, sys.modules est toujours un dictionnaire de tous les modules chargés, donc au moins il y a toujours une référence.

Edit: Mais il existe un moyen de recharger un module, imp.reload.

Malheureusement, je ne peux pas le faire fonctionner dans ce cas, le rechargement a besoin du module aléatoire (probablement pour créer une partie du fichier compilé Python), le module aléatoire a besoin de math.cos, Et c'est parti. Même avec l'importation de random d'abord, il n'y a pas d'erreur, mais math.cos ne réapparaît pas; Je ne sais pas pourquoi, peut-être parce que c'est un module intégré.

15
RemcoGerlich