This article turns from: https://wiki.woodpecker.org.cn/moin/MiscItems/2008-11-25 issues
Cleven <[email protected]>
Reply to [email protected] recipient [email protected] Date November 25, 2008 PM 12:01 keynote [cpyug:72341] Issues with import nesting
Read the "Python Source Code Analysis", the problem of nested import mentioned in the question still did not understand, you look at it.
[a.py] From B import Dclass C:pass[b.py] fromA import Cclass D:pass
Why can't I load D when I execute a?
If you change a.py to: Import B.
What's going on here?
Robert Chen: An explanation
Robert Chen <[email protected]om> replies to [email protected] recipient [email protected] date November 25, 2008 afternoon 1:41 keynote [cpyug:72362] re:import nesting issues
Well, this is related to Python's internal import mechanism, which is divided into several steps within the From B import D,python:
- Find Symbol "B"
-
If symbol B is present, get the module object corresponding to symbol b <module b>
-
if symbol B does not exist, create a new module object <module B Note that at this point, the module object's __dict__ is empty
So the order of execution for this example is as follows:
1, the implementation of the a.py in the From B import DBecause the Python a.py is executed, there is no <module b> in the Sys.modules,First, create a Module object (<module b>) for b.py,Note that the module object created at this time is empty and there is nothing inside,After the module object is created inside Python, the execution b.py is parsed to populate the dict of <module b>. 2, execute b.py from a import c in the course of implementing b.py, you will encounter this sentence, Span id= "line-9" class= "anchor" > first check if Sys.modules <module is already present in this module cache, because at this time the cache has not been cached <module a>, so similarly, Inside Python, a Module object (<module a>) is created for a.py, 3, re-execute a.py in from B import D at this point, because the <module b> object that was created in the 1th step is already in the Sys.modules, so directly got <module b>, But, notice, from the whole process, we know , then <module b> is still an empty object, inside nothing, So the operation of getting the symbol "D" from this module throws an exception. If this is only import B, because the "B" symbol already exists in sys.modules, it will not throw an exception.
ZQ: Illustration
Compile Trace
Diary of Hiter:
The problem code is as follows:
a.py fromA import Bclass B (object):pthe >>> import ATraceback (most recent): File "& Lt;stdin> ", line 1, in <module> File"/home/john/pythonstudy/mypython/bin/a.py ", line 9, in <module>< c7> from A import bimporterror:cannot import name B>>>
After reading the code, I found:byte code probably
9 0 Load_const 0 (-1)3 Load_const 1 ((' B ',))6 Import_name 0 (A)9 Import_from 1 (B)1 Store_name (B)Pop_top ten Load_const 2 (' B ') Load_name 2 (object) Build_tuple 1 Load_const 3 (<code object B at 0xb7a1fa88, file "a.py", line 10>) Make_function 0 34 Build_class Store_name 1 (B) Load_const 4 (' Hi ') " Print_item Print_newline Load_const 5 (None) Return_value
- You can see the whole import process is: First import a, and then import a and then error.
The analysis found that the reason is: at import a, the virtual machine found Sys.modules (check in import_submodule) did not load a, and then new a module, the new module is empty, you need to add __ builtin__,__file__ attributes (when executing the next import, the new module's dict will be passed as globals (locals) to execute (A) bytecode), The virtual machine then joins the new module in Sys.modules, at which point the call stack for the VM is as follows: (the line number of the code may be incorrect because many debug output codes are added to the source code)
#0 pyimport_addmodule (name=0xbfd91673 "A") at python/import.c:617 <-------Pyimport_addmodule here#1 0x08106271 in Pyimport_execcodemoduleex (name=0xbfd91673 "A", co=0xb7da6748, pathname=0xbfd8f533 "A.pyc") at Python/i mport.c:653#2 0x08106c67 in Load_source_module (name=0xbfd91673 "A", pathname=0xbfd8f533 "A.pyc", Fp=0x821bd60) at Python/import.c: 963#3 0x081085cf in Load_module (name=0xbfd91673 "A", Fp=0x821bd60, Buf=0xbfd905d3 "a.py", type=1, loader=0x0) at Python/imp ort.c:1753#4 0x0810a39b in Import_submodule (mod=0x818c888, subname=0xbfd91673 "a", fullname=0xbfd91673 "a") at Python/import.c:24 <--------Import_submodule is here#5 0x081098bb in Load_next (mod=0x818c888, altmod=0x818c888, p_name=0xbfd91654, buf=0xbfd91673 "A", p_buflen=0xbfd9166c )At python/import.c:2234#6 0x08108e1c in Import_module_level (name=0x0, GLOBALS=0XB7DE82B4, LOCALS=0XB7DE82B4, fromlist=0x818c888, Level=-1) at python/import.c:2005#7 0x081093a1 in Pyimport_importmodulelevel (name=0xb7de115c "A", Globals=0xb7de82b4, LOCALS=0XB7DE82B4, fromlist= 0x818c888, Level=-1)At python/import.c:2076#8 0x080d8809 in builtin___import__ (self=0x0, Args=0xb7d9de34, kwds=0x0) at python/bltinmodule.c:47#9 0x0814d04b in Pycfunction_call (FUNC=0XB7DCF5AC, Arg=0xb7d9de34, kw=0x0) at objects/methodobject.c:77#10 0x08062974 in Pyobject_call (FUNC=0XB7DCF5AC, Arg=0xb7d9de34, kw=0x0) at objects/abstract.c:1861#11 0x080ecad2 in Pyeval_callobjectwithkeywords (FUNC=0XB7DCF5AC, Arg=0xb7d9de34, kw=0x0) at python/ceval.c:3446#12 0x080e7b33 in Pyeval_evalframeex (F=0X821BC04, throwflag=0) at python/ceval.c:2068#13 0x080eaf9e in Pyeval_evalcodeex (Co=0xb7d9ab08, GLOBALS=0XB7DE82B4, LOCALS=0XB7DE82B4, args=0x0, argcount=0, kws= 0x0, Kwcount=0,defs=0x0, defcount=0, closure=0x0) at python/ceval.c:2840#14 0x080e013e in Pyeval_evalcode (Co=0xb7d9ab08, GLOBALS=0XB7DE82B4, LOCALS=0XB7DE82B4) at python/ceval.c:494#15 0x08116ab0 in Run_mod (mod=0x8220378, filename=0x81653bb "<stdin>", GLOBALS=0XB7DE82B4, LOCALS=0XB7DE82B4, Flags=0xbfd92f70, ARENA=0X81C5CD8) at python/pythonrun.c:1273 #16 0x081151e1 in Pyrun_interactiveoneflags (fp=0xb7f4d440, FILENAME=0X81653BB " <stdin> ", flags=0xbfd92f70) at Python/pythonrun.c:792 #17 0x08114e54 in Pyrun _interactiveloopflags (fp=0xb7f4d440, filename=0x81653bb "<stdin>", flags=0xbfd92f70) at PYTHON/PYTHONRUN.C : 723 #18 0X08114CAC in Pyrun_anyfileexflags (fp=0xb7f4d440, FILENAME=0X81653BB " <stdin> ", closeit=0, flags=0xbfd92f70) at Python/pythonrun.c:692 #19 0x08059d60 in Py_main (Argc=1, argv=0xbfd93074) at Modules/main.c:523 #20 0x08058e26 In Main (argc=136033156, ARGV=0XB7DC37B4) at./modules/python.c:23
You can create a new module and add it to sys.modules in the function Pyimport_execcodemoduleex, and then pass the dict of the new module as locals (globals) to the function that executes the A-byte code. When executing a bytecode, it is found that import_name A is required, and the virtual opportunity discovers that a is already present in the sys.modules, so it returns the module of a directly, and in the next import_from, it tries to find B from the module. At this time the module in the virtual machine only loaded __builtin__,__file__ properties, loading B's bytecode has not been executed (and can not be executed), so the virtual machine will throw an exception can not load B.
In the <python source code anatomy > Preface, the question is mentioned:
[a.py] From B import Dclass C: pass[b.py] fromA import Cclass D: pass
D cannot be loaded here, which is similar to the one raised at the beginning of this article.
Summarize:
-
The execution flow of the Import_name byte-code command is as follows
-
- Assuming that import a is required, the virtual machine first looks in sys.modules for a load of a,
- When found, the object is returned and the command ends;
- If not found, then the virtual opportunity to create a new module object,
Then add the necessary attributes (builtin, etc.) to the module object.
- Then use the Dict in this module as globals (locals) to execute a,
- and then return
Go Module looping import issues in Python