Ipython: Globale Variablen, die bei der interaktiven Verwendung der eingebetteten Ipython-Shell nicht definiert sind

Erstellt am 10. Mai 2010  ·  39Kommentare  ·  Quelle: ipython/ipython

Ursprünglicher Launchpad-Fehler 399627: https://bugs.launchpad.net/ipython/+bug/399627
Berichtet von: h-fangohr (Hans Fangohr).

Der Fehler kann wie folgt reproduziert werden:

  1. Starten Sie Python und starten Sie die eingebettete IPython-Sitzung. Wir folgen dem Handbuch von ipython
fangohr<strong i="11">@eta</strong>:~$ python
Python 2.4.3 (#1, Jun  8 2009, 14:09:06) 
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from IPython.Shell import IPShellEmbed
>>> ipshell=IPShellEmbed()
>>> ipshell()

In der gerade gestarteten Ipython-Sitzung sind globale Variablen manchmal nicht sichtbar. Zwei Beispiele sind:

Beispiel 1:

In [1]: a=1

In [2]: def f(x):
   ...:     return a*x
   ...: 

In [3]: f(2)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)

/home/fangohr/<ipython console> 

/home/fangohr/<ipython console> in f(x)

NameError: global name 'a' is not defined

Beispiel 2:

In [4]: b=1

In [5]: (lambda :b)()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)

/home/fangohr/<ipython console> 

/home/fangohr/<ipython console> in <lambda>()

NameError: global name 'b' is not defined

Es gibt keinen Fehler, wenn "b = 1; (lambda: b) ()" in ein Skript eingefügt wird und dieses Skript mit dem Befehl "run" von ipython ausgeführt wird.

Es gibt keinen Fehler, wenn "b = 1; (Lambda: b) ()" nach dem Start von ipython interaktiv ausgeführt wird.

Der Fehler tritt nur dann auf, wenn eine eingebettete IPython-Shell an einer Python-Eingabeaufforderung gestartet wird UND die Befehle an der Eingabeaufforderung interaktiv ausgeführt werden.

Ich finde den gleichen Fehler beim Versuch von ipython-0.9.1 (mit python2.4).

Der Fehler wurde von Olivier Klein dem nmag-Team gemeldet (http://nmag.soton.ac.uk).

bug

Hilfreichster Kommentar

Wie unter https://github.com/inducer/pudb/issues/103 angegeben , lautet eine vorübergehende Problemumgehung bei Verwendung einer eingebetteten Shell: globals().update(locals()) (nur nach Definition der lokal globalen Variablen).

Alle 39 Kommentare

[LP-Kommentar 1 von: Fernando Perez, am 25.04.2010 23: 36: 38.673176 + 00: 00]

OK, ich kann das Problem bestätigen (auch am Kofferraum), aber es ist schwer. Ich stelle erst einmal sicher, dass dieser Fehler bestätigt wird, damit wir ihn weiter verfolgen können, aber ich bin mir nicht sicher, wie ich ihn beheben soll.

Das Problem ist, dass wir in eingebetteten Shells versuchen, den globalen Namespace zu aktualisieren, um den umgebenden Bereich zu verwenden (das ist der Punkt einer eingebetteten Shell, um sehen zu können, was sich um Sie herum befindet). Dies führt dann jedoch dazu, dass Python den interaktiven ipython-Namespace nicht auflösen kann, wenn verschachtelte Elemente (wie lokale Funktionen) definiert sind. Weitere Informationen finden Sie in der mainloop () -Methode der eingebetteten Shell.

Ich muss viel mehr darüber nachdenken, wie ich dieses Problem beheben kann. Ideen sind sehr willkommen.

Drüben am Launchpad ...

ChairmanK schrieb vor 20 Stunden:

Ich auch. Zusätzlich zu den Funktionen tritt dieser Fehler auch in Generatorausdrücken auf.

Die äquivalente Komponente im Trunk scheint IPython.frontend.terminal.InteractiveShellEmbed zu sein. Aber das ist auf andere Weise kaputt und wurde offensichtlich nicht viel getestet. Weiß jemand, was seine Zukunft ist?

Könnte dies das gleiche Problem sein wie # 136?

Dies wurde jetzt behoben:

amirbar[ipython]> python
Python 2.7.2+ (default, Oct  4 2011, 20:06:09) 
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from IPython import embed
>>> embed()
Python 2.7.2+ (default, Oct  4 2011, 20:06:09) 
Type "copyright", "credits" or "license" for more information.

IPython 0.12.dev -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: a = 1

In [2]: def f(x):
   ...:     return a*x
   ...: 

In [3]: f(3)
Out[3]: 3

In [4]: b = 1

In [5]: (lambda : b)()
Out[5]: 1

In [6]: 

Kann jemand etwas mehr erklären, was dazu beigetragen hat? Ich stoße immer noch auf das Problem, aber nur, wenn ich eine Ebene über einen Methodenaufruf entfernt habe und nur, wenn ich über ein Skript ausgeführt werde, nicht interaktiv.

Python 2.7.2 unter OSX 10.6.8, Ipython 0.11 und 0.12 zeigen beide ein ähnliches Verhalten (unter Verwendung von 0.12 für diesen Kommentar)

Dies ist ein Problem bei unserem Projekt, das (prominent) eine eingebettete IPython-Shell enthält.

testembed.py

from IPython import embed

def hi():
    embed()

if __name__ == '__main__':
    #embed()
    hi()

Führen Sie dies in der Befehlszeile mit python testembed.py und sehen Sie sich diese Sitzung an:

Python 2.7.2 (default, Aug 29 2011, 12:33:18) 
Type "copyright", "credits" or "license" for more information.

IPython 0.12 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: import time

In [2]: def tim():
   ...:     print time.time()
   ...:     

In [3]: tim()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
[snip] in <module>()
----> 1 tim()

[snip] in tim()
      1 def tim():
----> 2     print time.time()
      3 

NameError: global name 'time' is not defined

In [4]: 

Kommentieren Sie jedoch den Aufruf von hi() und ersetzen Sie ihn durch den Aufruf von embed() :

Python 2.7.2 (default, Aug 29 2011, 12:33:18) 
Type "copyright", "credits" or "license" for more information.

IPython 0.12 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: import time

In [2]: def tim():
    print time.time()
   ...:     

In [3]: tim()
1328639444.29

In [4]: 

Nach dem Stöbern hat es meiner Meinung nach mit dem hier verwendeten Parameter stack_depth und diesem Block zu tun: https://github.com/ipython/ipython/blob/master/IPython/frontend/terminal/embed.py # L185

Gedanken?

Das ist etwas kompliziert, aber ich glaube, das ist eine Einschränkung in Python.

In dem fehlgeschlagenen Fall, den Sie anzeigen, wird time nicht tatsächlich in den globalen Namespace eingefügt: Da Sie in der Funktion hi embed aufgerufen haben, sind neue Variablen, die Sie interaktiv erstellen, lokal dafür Funktion. Im Idealfall sollte tim() als Abschluss fungieren und über den Verweis auf das Zeitmodul schließen. Schließungen scheinen jedoch nur zu funktionieren, wenn die enthaltende Funktion auf einmal kompiliert wird. Soweit ich das beurteilen kann, gibt es keine Möglichkeit, einen Abschluss dynamisch zu definieren. Dieses einfache Beispiel schlägt fehl:

def outer():
    import time
    exec("def inner(): return time.time()")
    return inner

outer()()

Dies liegt wahrscheinlich daran, dass verschachtelte Bereiche relativ spät zu Python hinzugefügt wurden (sie waren ein zukünftiger Import in 2.1 und immer in 2.2).

Ok, ich glaube ich verstehe. Es sieht so aus, als könnten wir dann nichts dagegen tun, außer das, was ich interaktiv in eine Datei schreiben würde, zu speichern und diese Datei dann wieder einzulesen. Wahrscheinlich zu komplex für das, was wir interaktiv tun möchten.

Danke übrigens.

Es tut mir leid, hier weiter zu spielen, aber dadurch fühlen sich interaktive Sitzungen nur sehr klobig an:

Regelmäßige Python:

>>> d={'one':1, 'two':2}
>>> getkeys=lambda: d.keys()
>>> getkeys()
['two', 'one']

Normales IPython:

In [1]: d={'one':1, 'two':2}

In [2]: getkeys=lambda: d.keys()

In [3]: getkeys()
Out[3]: ['two', 'one']

Eingebettetes IPython:

>>> from IPython import embed
>>> embed()
Python 2.7.2 (default, Aug 29 2011, 12:33:18) 
Type "copyright", "credits" or "license" for more information.

IPython 0.12.dev -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: d={'one':1, 'two':2}

In [2]: getkeys=lambda: d.keys()

In [3]: getkeys()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/Users/asadeveloper/Documents/Dev/code/pyon/bin/python in <module>()
----> 1 getkeys()

/Users/asadeveloper/Documents/Dev/code/pyon/bin/python in <lambda>()
----> 1 getkeys=lambda: d.keys()

NameError: global name 'd' is not defined

Ich denke, es kann nicht viel getan werden, aber ich verstehe nicht, warum wir einen dynamischen Abschluss in regulärem Python / Ipython erstellen können, aber nicht in der eingebetteten Version.

Aufgrund der Kuriositäten des Python-Scoping erstellen wir in Standard-Python / IPython keinen Abschluss. d ist eine globale Variable, und die Regeln für den Zugriff auf diese funktionieren anders als bei Schließungen. Jede Funktion behält einen Verweis auf den globalen Namespace bei, in dem sie definiert wurde ( getkeys.func_globals ), sodass sie auf alle dort definierten Variablen zugreifen kann.

Im Gegensatz dazu fügt Python beim Schließen Verweise auf jede Variable hinzu, über die es geschlossen hat, wie vom Compiler festgelegt. Dies funktioniert jedoch nur, wenn die inneren und äußeren Funktionen gleichzeitig kompiliert werden. Es sieht aus wie das:

In [8]: def outer():
    a = 1
    def inner():
        return a
    return inner
   ...: 

In [9]: f = outer()

In [10]: f
Out[10]: <function __main__.inner>

In [11]: f.func_closure
Out[11]: (<cell at 0x9f5e344: int object at 0x9a830b0>,)

Dies geschieht möglicherweise, um Speicherplatz zu sparen. Wenn der Abschluss einen Verweis auf den lokalen Bereich enthält, in dem er definiert wurde, konnte keine der Variablen aus diesem Bereich freigegeben werden, während der Abschluss aktiv war.

Ich verwende Python 2.7.2 und IPython 0.12.1 unter OSX 10.7.3 und habe dieses Problem immer noch. Wenn ich laufen ./manage.py shell von Django , die ruft IPython.embed() , tritt das Problem. Das manuelle Aufrufen von embed() in der Python-Shell oder aus einer einfachen Skriptdatei ist jedoch kein Problem.

Wir können nicht viel direkt dagegen tun, aber wir sollten wahrscheinlich Dritte dazu ermutigen, sich für nicht triviale Zwecke von embed fernzuhalten.

@takluyver Meinst du, dass es in diesem Fall besser ist, ipython direkt zu verwenden?

Es ist für Django möglich, IPython auf eine Weise zu starten, die dieses Problem nicht verursacht, aber so machen wir es derzeit nicht einfach. Das Problem tritt auf, wenn IPython mit separaten lokalen und globalen Namespaces beginnt. Es gibt keinen Grund, warum Django separate lokale und globale Namespaces benötigt, aber genau das impliziert der Aufruf von embed() innerhalb einer Funktion.

Als Referenz ist hier der Code in Django:
https://code.djangoproject.com/browser/django/trunk/django/core/management/commands/shell.py

@takluyver Das macht Sinn, danke! Ich öffne dafür ein Django-Ticket.

@takluyver , jetzt, da wir embedded_kernel zusammengeführt haben, damit alle Hauptteile vorhanden sind, möchten Sie ein wenig aufräumen, um die Feinabstimmung der Verwendung zu vereinfachen?

Ich werde mir ansehen, welche Benutzeroberfläche am sinnvollsten ist.

Ich habe immer noch Probleme mit diesem Problem. Ich habe versucht, genau einzugrenzen, was es verursacht, und das Beste, was ich feststellen kann, ist, dass es nur unter Ubuntu 12.04 passiert. Ich habe alle aktuellen Release-Versionen auf anderen Servern ausprobiert und es funktioniert einwandfrei. Aber jedes Mal, wenn ich eine Funktion in ipython definiere oder% cpaste verwende, um eine Funktion aus einer anderen Datei einzufügen, hat das Innere dieser Funktion keinen Zugriff auf den globalen Bereich. Es macht es im Grunde unmöglich, irgendetwas Nützliches in Bezug auf Schreibfunktionen im laufenden Betrieb zu tun.

Ich habe immer noch dieses Problem mit IPython 0.13, wenn es von anderen Tools aufgerufen wird (z. B. Djangos Befehl debugsqlshell). Es ist sehr frustrierend, dass etwas so Grundlegendes wie das Definieren einer Funktion völlig kaputt ist.

Ich denke, embedded () ist die falsche Schnittstelle für diejenigen, die sie verwenden. embedded () ist
eher dazu gedacht, den Status eines laufenden Programms zu untersuchen, also verwendet es
getrennte lokale und globale Namespaces. Um dieses Problem zu umgehen, ipython
muss mit einer einzigen Schnittstelle gestartet werden. Entschuldigung, ich hatte keine Zeit dafür
Finde heraus, wie es am besten geht.

Nicht nur Ubuntu. debian wheezy zeigt das auch.

Zu Ihrer Information, das oben erstellte Django-Ticket https://code.djangoproject.com/ticket/18204 und verweist nun auf https://code.djangoproject.com/ticket/17078 , das anscheinend im Trunk behoben wurde . Es sollte in 1.5 landen.

Ich habe das gleiche Problem unter Ubuntu mit Ipython 0.13.2
screenshot from 2013-08-07 18 13 33

@bkvirendra , das in Django 1.6 behoben ist

Aber 1.6 ist noch nicht einmal stabil!

Aber 1.6 ist noch nicht einmal stabil!

Software ist nicht immer stabil und zwischen den Versionen können immer noch Fehler auftreten. In IPython sollte jedoch nichts behoben werden. Selbst wenn wir hier etwas tun, wäre das Update nicht in IPython stabil, bevor es veröffentlicht wird ...

Das Problem besteht weiterhin in ipython == 4.2.0. Interessanterweise ist es unter Windows kein Problem, aber zusammen mit Ubuntu werden globale Variablen nicht erkannt.

Anwendungsfall:

from ipywidgets import interact, FloatSlider, IntSlider,RadioButtons, Dropdown

@interact(sv1 = radio_1, Scenario = drop_1, sv2 = slider_2)
def update_map(sv1,sv2, Scenario):

Problem bleibt bestehen. IPython 3.1.0, Debian Whezzy.

Wenn ich mich richtig erinnere, wurde dies für eine Weile behoben und scheint wieder eingeführt zu werden (reproduziert mit IPython 5.1.0 unter macOS hier: https://git.io/vPDrJ).

(Bearbeiten: Ich erinnere mich möglicherweise falsch an das Update. Möglicherweise habe ich einfach alles, was ich brauchte, in eine Startdatei geworfen, anstatt Embed zu verwenden.)

Nur für den Fall, dass dies jemandem hilft, habe ich diesen Code als Problemumgehung verwendet

    def fix_embed_globals(N=0):
        # Get the parent frame
        import inspect
        frame_level0 = inspect.currentframe()
        frame_cur = frame_level0
        N = 2  # I may have this value off by one. I rewrote this function to use only standard calls
        strict = False
        for _ix in range(N + 1):
            frame_next = frame_cur.f_back
            if frame_next is None:
                if strict:
                    raise AssertionError('Frame level %r is root' % _ix)
                else:
                    break
            frame_cur = frame_next
        parent_frame = frame_cur
        # Add locals to parent globals
        parent_frame.f_locals.update(parent_frame.f_globals)
        parent_frame.f_globals['_didfixipyglobals'] = True

Ich rufe diese Funktion einfach auf, wenn ich den Namensfehler erhalte. Es fügt alle Einheimischen in Ihrem aktuellen Frame in das globale Wörterbuch ein. Es ist hacky, aber es funktioniert in den meisten Fällen.

Wie unter https://github.com/inducer/pudb/issues/103 angegeben , lautet eine vorübergehende Problemumgehung bei Verwendung einer eingebetteten Shell: globals().update(locals()) (nur nach Definition der lokal globalen Variablen).

Hmm, kann der Meilenstein dieses Fehlers auf eine der nächsten Versionen geändert werden?

Getan.

Wird dies jemals behoben werden?

AFAIK, meine Kommentare von vor ein paar Jahren stehen:

  1. Ich glaube, wir sind durch die Funktionsweise von Python selbst eingeschränkt. Abschlüsse und dynamische Auswertung spielen nicht gut zusammen, und IPython kann dies nicht beheben. Die Benutzer haben Problemumgehungen gefunden, um lokale Variablen in einen globalen Namespace zu verschieben. Dies sind jedoch Hacks, die andere Probleme verursachen können, da sie den globalen Namespace ändern. Ich habe nicht vor, solche Problemumgehungen in IPython einzufügen. Ich möchte lieber ein Problem mit etwas hinterlassen, das wir nicht tun, als eines einzuführen, indem ich versuche, zu klug zu sein.

  2. An vielen Orten, an denen die Leute dachten, sie wollten embed() , sollten sie stattdessen start_ipython() verwenden und diese Art von Problem vermeiden.

Ich verstehe nicht und es macht mich wütend.

Entschuldigung, ich war frustriert, dass Dinge, die funktionieren würden, wenn Sie sie in eine leere .py-Datei eingeben würden, hier nicht funktionieren würden

Aber wenn ich die Geschichte noch einmal lese, scheint es, dass dies ein Problem mit Djangos manage.py shell ist. 90% der Zeit, in der ich in Ipython bin, mache ich das, aber es ist leicht zu vergessen, dass dies der Fall ist

peinlich, ich arbeite viel in einer veralteten Version von Django (1.4)

Laut früheren Kommentaren verwenden neuere Versionen der Django-Shell Ipython anders und haben möglicherweise nicht das Problem? zB https://code.djangoproject.com/ticket/17078

Entschuldigung für das Missverständnis

Ja, ich denke, es wurde für Django 1.6 behoben. Wenn Sie wirklich kein Upgrade durchführen können, können Sie das Update manuell anwenden. Es sieht so aus, als wäre es das: https://github.com/django/django/commit/3570ff734e93f493e023b912c9a97101f605f7f5

Ich habe heute eine Problemumgehung gefunden, die unter diesem Thread gezeigt . Ich bin kein Experte. Bitte helfen Sie bei der Überprüfung der Gültigkeit.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen