webentwicklung-frage-antwort-db.com.de

Python: Komponente Y neu laden, importiert mit 'from X import Y'?

Wenn ich in Python ein Modul X mit import X in eine Interpreter-Sitzung importiert habe und das Modul außen geändert wird, kann ich das Modul mit reload(X) erneut laden. Die Änderungen stehen dann in meiner Dolmetschersitzung zur Verfügung.

Ich frage mich, ob dies auch möglich ist, wenn ich eine Komponente Y mit from X import Y aus Modul X importiere.

Die Anweisung reload Y funktioniert nicht, da Y kein Modul selbst ist, sondern nur eine Komponente (in diesem Fall eine Klasse) innerhalb eines Moduls.

Ist es überhaupt möglich, einzelne Komponenten eines Moduls nachzuladen, ohne die Interpretersitzung zu verlassen (oder das gesamte Modul zu importieren)?

BEARBEITEN:

Zur Verdeutlichung geht es darum, eine Klasse oder Funktion Y aus einem Modul X zu importieren und bei einer Änderung neu zu laden, nicht ein Modul Y aus einem Paket X.

67
cschol

Wenn Y ein Modul ist (und X ein Paket), wird reload(Y) in Ordnung sein - ansonsten werden Sie sehen, warum gute Python-Style-Guides (wie mein Arbeitgeber) niemals etwas importieren außer einem Modul sagen (Dies ist einer von vielen guten Gründen - dennoch importieren die Leute weiterhin Funktionen und Klassen direkt, egal wie viel ich erkläre, dass es nicht eine gute Idee ist ;-).

44
Alex Martelli

Antworten

Aus meinen Tests. Die markierte Antwort, die auf eine einfache reload(X) hindeutet, funktioniert nicht.

Von dem, was ich sagen kann, ist die richtige Antwort:

import X
reload( X )
from X import Y

Prüfung

Mein Test war der folgende (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

Erstens sollten Sie Reload überhaupt nicht verwenden, wenn Sie es vermeiden können. Nehmen wir jedoch an, Sie haben Ihre Gründe (d. H. Debugging in IDLE).

Durch das erneute Laden der Bibliothek werden die Namen nicht wieder in den Namensraum des Moduls übernommen. Um dies zu tun, weisen Sie die Variablen einfach neu zu:

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

Sie könnten dies auf andere Weise tun. Sie könnten den Prozess automatisieren, indem Sie den lokalen Namensraum durchsuchen und alles, was aus dem fraglichen Modul stammt, neu zuweisen, aber ich denke, wir sind böse genug.

7
wisty
from modulename import func

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

Wenn du das machen willst:

from mymodule import myobject

Tun Sie dies stattdessen:

import mymodule
myobject=mymodule.myobject

Sie können myobject jetzt auf die gleiche Weise verwenden, wie Sie es geplant haben (ohne die langwierigen unlesbaren Referenzmodule).

Wenn Sie interaktiv arbeiten und myobject von mymodule nachladen möchten, können Sie jetzt Folgendes verwenden:

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

wenn Sie from X import Y verwendet haben, haben Sie zwei Möglichkeiten:

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

oder

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

einige Überlegungen:

A. Wenn der Importumfang nicht modulweit ist (z. B. Import in einer Funktion), müssen Sie die zweite Version verwenden.

B. wenn Y aus einem anderen Modul (Z) in X importiert wird - Sie müssen Z neu laden, dann X erneut laden und dann Ihr Modul erneut laden. Sogar alle Ihre Module (z. B. mit [ reload(mod) for mod in sys.modules.values() if type(mod) == type(sys) ]) müssen neu geladen werden, bevor Sie Z und neu laden als den Wert von Y nicht aktualisieren.

2
Ohad Cohen
  1. reload() Modul X,
  2. reload() Modul importiert Y aus X.

Beachten Sie, dass beim erneuten Laden bereits erstellte Objekte, die an andere Namespaces gebunden sind, nicht geändert werden (auch wenn Sie den Style-Guide von Alex folgen).

1
Denis Otkidach

Wenn Sie in einer Jupyter-Umgebung arbeiten und bereits from module import function haben, können Sie die Zauberfunktion autoreload von verwenden

%load_ext autoreload
%autoreload
from module import function

Die Einführung von autoreload in IPython erfolgt hier .

0
Yanqi Huang

Um auf die Antworten von AlexMartelli und Catskul's einzugehen, gibt es einige wirklich einfache, aber unangenehme Fälle, die reload zumindest in Python 2 zu verwirren scheinen.

Angenommen, ich habe den folgenden Quellbaum:

- foo
  - __init__.py
  - bar.py

mit folgendem Inhalt:

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)

Dies funktioniert auch ohne reload:

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

Versuchen Sie jedoch, neu zu laden, und dies hat entweder keine Auswirkungen oder beschädigt die Dinge:

>>> 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

Die einzige Möglichkeit, sicherzustellen, dass das bar-Modul erneut geladen wurde, war reload(foo.bar); Die einzige Möglichkeit, auf die reloaded-Klasse Quux zuzugreifen, besteht darin, sie aus dem reloaded-Untermodul herauszuholen und zu ergreifen. Das foo-Modul selbst hielt jedoch an dem ursprünglichen Quux-Klassenobjekt fest, vermutlich weil es from bar import Bar, Quux (anstelle von import bar, gefolgt von Quux = bar.Quux) verwendet. außerdem änderte sich die Quux-Klasse nicht mit sich selbst, was nur bizarr ist.

0
Jason S