import 会执行 被 import 文件的代码
我们先构建个例子
[gateman@manjaro-x13 python_common_import]$ tree
.
├── pytest.ini
├── README.md
├── requirement.txt
├── src
│ └── import_base
│ ├── __init__.py
│ ├── m1.py
│ └── run1.py
└── test
└── test_1.py
如上, 新建了1个项目, 在 src/import_base/ 里有两个文件, m1.py 和 run1.py
m1.py
import os
filename = os.path.basename(__file__)
print("it's in {}".format(filename))
def f1(from_file=filename):
print("f1 in {} called from {}".format(filename, from_file))
f1()
run1.py
import os
import m1
filename = os.path.basename(__file__)
m1.f1(filename)
可以看出, run1.py 调用里 m1.py的f1()方法,
Note: _file_ 会 return 当前文件的full path
执行测试 m1.py
(.venv) [gateman@manjaro-x13 python_common_import]$ python src/import_base/m1.py
it's in m1.py
f1 in m1.py called from m1.py
输出正常
执行测试 run1.py
(.venv) [gateman@manjaro-x13 python_common_import]$ python src/import_base/run1.py
it's in m1.py
f1 in m1.py called from m1.py
f1 in m1.py called from run1.py
这时, 发现除了run1 调用 m1.f1()的输出外, 之前还包含了m1.py 自己本身的输出!
所以import m1
实际上会执行m1.py 里所有的代码
多次import 同1个模块不会重复执行该模块的代码.
例如我把 run1.py改成
import os
import m1
import m1
filename = os.path.basename(__file__)
m1.f1(filename)
注意这里import了两次m1
但是实际输出还是只会执行1次m1的代码
(.venv) [gateman@manjaro-x13 python_common_import]$ python src/import_base/run1.py
it's in m1.py
f1 in m1.py called from m1.py
f1 in m1.py called from run1.py
所以python 有1个机制, 当某个模块已经被import时, 再次import 并不会重复执行。
import x 和 from x import 的区别
我修改以下m1.py 和 run1.py
m1.py
filename = os.path.basename(__file__)
print("it's in {}".format(filename))
def f1(from_file=filename):
print("f1 in {} called from {}".format(filename, from_file))
def f2(from_file=filename):
print("f2 in {} called from {}".format(filename, from_file))
f1()
f2()
run1.py
import os
import m1
filename = os.path.basename(__file__)
m1.f1(filename)
m1.f2(filename)
无非增加了1个函数调用f2()
当执行run1.py时, 输出如下:
(.venv) [gateman@manjaro-x13 python_common_import]$ python src/import_base/run1.py
it's in m1.py
f1 in m1.py called from m1.py
f2 in m1.py called from m1.py
f1 in m1.py called from run1.py
f2 in m1.py called from run1.py
f1 和 f2 都被调用了
由dir() 决定能不能直接调用某个对象
这次我修改以下run1.py
run1.py
import os
import m1
filename = os.path.basename(__file__)
m1.f1(filename)
f2(filename)
注意f2前面没有m1. prefix
测试时会有error
(.venv) [gateman@manjaro-x13 python_common_import]$ python src/import_base/run1.py
it's in m1.py
f1 in m1.py called from m1.py
f2 in m1.py called from m1.py
f1 in m1.py called from run1.py
Traceback (most recent call last):
File "/home/gateman/Projects/python/python_common_import/src/import_base/run1.py", line 6, in <module>
f2(filename)
^^
NameError: name 'f2' is not defined
原因很简单, f2 没有定义, 而m1是定义过的。
查看一个模块本身哪些对象已经定义可以 用 dir()方法
再次修改run1.py
import os
import m1
filename = os.path.basename(__file__)
print("defined objects list: {}".format(dir()))
m1.f1(filename)
f2(filename)
加了一行dir()的输出
测试结果:
(.venv) [gateman@manjaro-x13 python_common_import]$ python src/import_base/run1.py
it's in m1.py
f1 in m1.py called from m1.py
f2 in m1.py called from m1.py
defined objects list: ['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'filename', 'm1', 'os']
f1 in m1.py called from run1.py
Traceback (most recent call last):
File "/home/gateman/Projects/python/python_common_import/src/import_base/run1.py", line 7, in <module>
f2(filename)
^^
NameError: name 'f2' is not defined
可以见到 dir()里面的对象除了一些built-in的东西
‘annotations’, ‘builtins’, ‘cached’, ‘doc’, ‘file’, ‘loader’, ‘name’, ‘package’, ‘spec’
之外
还有, filename, m1, os 3个
其中m1 和 os 都是import 进来的, filename 是在文件内定义的, 所以都能被调用。
而f2不在其中.
所以 为何m1.f2() 能调用, 直接f2()会出错
from x import 写法能直接调用函数/对象名字, 而不需要带模块名
再修改一次run1.py
import os
from m1 import f2
filename = os.path.basename(__file__)
print("defined objects list: {}".format(dir()))
f2(filename)
m1.f1(filename)
这次我们把import m1 改成 from m1 import f2
结果很明显, f2能直接被调用了 但是m1.f1()失败, 因为m1 并不在dir()里面, 而且直接调用f1()也是不行的, 因为只从m1里引用了f2()
而且from m1 import f2() 看来只引用了f2, 但是实际上还是会执行 m1的全部代码的.
.venv) [