理解 python 中的 import

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) [
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nvd11

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值