web-dev-qa-db-fra.com

Python: recharger le composant Y importé avec 'from X import Y'?

En Python, une fois que j'ai importé un module X dans une session d'interprétation en utilisant import X et que le module a été modifié à l'extérieur, je peux recharger le module avec reload(X). Les modifications deviennent alors disponibles dans ma session d’interprète.

Je me demande si cela est également possible lorsque j'importe un composant Y du module X à l'aide de from X import Y.

L'instruction reload Y ne fonctionne pas, car Y n'est pas un module, mais seulement un composant (dans ce cas, une classe) à l'intérieur d'un module.

Est-il possible de recharger des composants individuels d'un module sans quitter la session d'interprétation (ou importer le module entier)?

MODIFIER:

Pour plus de clarté, la question concerne l'importation d'un classe ou fonction Y à partir d'un module X et le rechargement d'une modification, pas un module Y à partir d'un package X.

67
cschol

Si Y est un module (et X un paquet) reload(Y) ira bien - sinon, vous verrez pourquoi les bons guides de style Python (tels que ceux de mon employeur) disent à jamais importer quoi que ce soit sauf un module (C’est l’une des nombreuses bonnes raisons - mais les gens continuent d’importer directement des fonctions et des classes, peu importe le nombre de fois où j’explique que c’est pas une bonne idée ;-).

44
Alex Martelli

Réponse

De mes tests. La réponse marquée, qui suggère un simple reload(X), ne fonctionne pas.

D'après ce que je peux dire, la réponse correcte est:

import X
reload( X )
from X import Y

Tester

Mon test était le suivant (Python 2.6.5 + bpython 0.9.5.2)

X.py:

def Y():
    print "Test 1"

bpython:

>>> from X import Y
>>> print Y()
Test 1
>>> # Edit X.py to say "Test 2"
>>> print Y()
Test 1
>>> reload( X )  # doesn't work because X not imported yet
Traceback (most recent call last):
  File "<input>", line 1, in <module>
NameError: name 'X' is not defined
>>> import X
>>> print Y()
Test 1
>>> print X.Y()
Test 1
>>> reload( X ) # No effect on previous "from" statements
>>> print Y()
Test 1
>>> print X.Y() # first one that indicates refresh
Test 2
>>> from X import Y
>>> print Y()
Test 2 
>>> # Finally get what we were after
74
Catskul

Tout d’abord, vous ne devriez pas du tout utiliser reload si vous pouvez l’éviter. Mais supposons que vous ayez vos raisons (c'est-à-dire le débogage dans IDLE).

Le rechargement de la bibliothèque ne récupérera pas les noms dans l'espace de noms du module. Pour ce faire, il suffit de réaffecter les variables:

f = open('Zoo.py', 'w')
f.write("snakes = ['viper','anaconda']\n")
f.close()

from Zoo import snakes
print snakes

f = open('Zoo.py', 'w')
f.write("snakes = ['black-adder','boa constrictor']\n")
f.close()

import Zoo
reload(Zoo)
snakes = Zoo.snakes # the variable 'snakes' is now reloaded

print snakes

Vous pouvez le faire de quelques autres manières. Vous pouvez automatiser le processus en effectuant une recherche dans l'espace de noms local et en réaffectant tout ce qui provient du module en question, mais je pense que nous sommes assez pervers.

7
wisty
from modulename import func

import sys
reload(sys.modules['modulename'])
from modulename import func
7
mirek

Si vous voulez faire ceci:

from mymodule import myobject

Faites ceci à la place:

import mymodule
myobject=mymodule.myobject

Vous pouvez maintenant utiliser myobject de la même manière que vous l'aviez prévu (sans les références illisibles et illisibles de mymodule partout).

Si vous travaillez de manière interactive et souhaitez recharger myobject à partir de mymodule, vous pouvez maintenant utiliser:

reload(mymodule)
myobject=mymodule.myobject
4
Chris Fryer

en supposant que vous avez utilisé from X import Y, vous avez deux options:

reload(sys.modules['X'])
reload(sys.modules[__name__]) # or explicitly name your module

ou

Y=reload(sys.modules['X']).Y

quelques considérations:

A. si la portée de l'importation n'est pas au niveau du module (par exemple, importation dans une fonction), vous devez utiliser la deuxième version.

B. si Y est importé dans X depuis un autre module (Z) - vous devez recharger Z, recharger X et recharger votre module, même recharger tous vos modules (par exemple, en utilisant [ reload(mod) for mod in sys.modules.values() if type(mod) == type(sys) ]) pourrait recharger X avant de recharger Z - et que de ne pas actualiser la valeur de Y.

2
Ohad Cohen
  1. reload() module X,
  2. Module reload() important Y à partir de X.

Notez que le rechargement ne changera pas les objets déjà créés liés dans d'autres espaces de noms (même si vous suivez le guide de style d'Alex).

1
Denis Otkidach

Si vous travaillez dans un environnement Jupyter et que vous possédez déjà from module import function pouvez utiliser la fonction magique, autoreload de

%load_ext autoreload
%autoreload
from module import function

L'introduction du autoreload dans IPython est donnée ici .

0
Yanqi Huang

Pour faire suite à AlexMartelli et Catskul à ses réponses, il existe des cas très simples mais méchants qui semblent confondre reload, du moins dans Python 2.

Supposons que j'ai l'arbre source suivant:

- foo
  - __init__.py
  - bar.py

avec le contenu suivant:

init.py:

from bar import Bar, Quux

bar.py:

print "Loading bar"

class Bar(object):
  @property
  def x(self):
     return 42

class Quux(Bar):
  object_count = 0
  def __init__(self):
     self.count = self.object_count
     self.__class__.object_count += 1
  @property
  def x(self):
     return super(Quux,self).x + 1
  def __repr__(self):
     return 'Quux[%d, x=%d]' % (self.count, self.x)

Cela fonctionne très bien sans utiliser reload:

>>> from foo import Quux
Loading bar
>>> Quux()
Quux[0, x=43]
>>> Quux()
Quux[1, x=43]
>>> Quux()
Quux[2, x=43]

Mais essayez de recharger et cela n’a aucun effet ou corrompt les choses:

>>> import foo
Loading bar
>>> from foo import Quux
>>> Quux()
Quux[0, x=43]
>>> Quux()
Quux[1, x=43]
>>> reload(foo)
<module 'foo' from 'foo\__init__.pyc'>
>>> Quux()
Quux[2, x=43]
>>> from foo import Quux
>>> Quux()
Quux[3, x=43]
>>> reload(foo.bar)
Loading bar
<module 'foo.bar' from 'foo\bar.pyc'>
>>> Quux()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "foo\bar.py", line 17, in __repr__
    return 'Quux[%d, x=%d]' % (self.count, self.x)
  File "foo\bar.py", line 15, in x
    return super(Quux,self).x + 1
TypeError: super(type, obj): obj must be an instance or subtype of type
>>> Quux().count
5
>>> Quux().count
6
>>> Quux = foo.bar.Quux
>>> Quux()
Quux[0, x=43]
>>> foo.Quux()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "foo\bar.py", line 17, in __repr__
    return 'Quux[%d, x=%d]' % (self.count, self.x)
  File "foo\bar.py", line 15, in x
    return super(Quux,self).x + 1
TypeError: super(type, obj): obj must be an instance or subtype of type
>>> foo.Quux().count
8

La seule manière de pouvoir recharger le sous-module bar était de reload(foo.bar); le seul moyen d’accéder à la classe Quux rechargée est d’atteindre et de le saisir à partir du sous-module rechargé; mais le module foo a lui-même conservé l'objet Quux d'origine, probablement parce qu'il utilise from bar import Bar, Quux (plutôt que import bar suivi de Quux = bar.Quux); De plus, la classe Quux est désynchronisée avec ce qui est bizarre.

0
Jason S