在Python中,我们总是使用import来导入另一个模块(文件)的内容。如果你是Java或者C转过来的程序员,有几个常见的坑要注意:import也是一个执行语句,可以在代码的任何部分执行。如果我们把import写在代码中间,IDE很可能会给出警告,但是只要逻辑正确,就忽略它:importaif__name__=="__main__":importbb.methodx()类似于上面的代码,只在当前文件作为主模块运行时,引入了模块b,这样既减少了浪费,又避免了循环引用。在执行import的时候,如果是第一次import,那么对应的模块会执行一次,这个模块中所有的顶层代码都会被执行,所以是一个非常耗时的操作,完全不同于Java或C,后者仅获取类型定义。;所以对于那些被复用的模块,需要尽量减少顶层代码块中的逻辑实现。即使在同一个模块中,代码定义的顺序也很重要,被引用的代码必须在引用之前定义,例如:classA:x:int=5classB:def__init__(self,y:A):self.y=yif__name__=="__main__":a=A()b=B(a)print(b.y.x)上面代码中,A类的定义不能放在B类之后,否则运行时会报错.提示name'A'isnotdefined;当然,如果只是在annotation中引用的话,可以通过from__future__importannotations来解决,那就是另外一个问题了。下面的内容表达有误,但这个错误有点典型,还是保留了下来。底部会说明:import的命名空间也很重要。不同的命名空间将被视为不同的模块。而一个模块,无论是绝对路径还是相对路径导入,都会被识别为不同的命名空间,比如下面的包结构:module_a的内容如下:a={"value":15}print(f'a={a}inmodule_a')module_b将使用绝对路径引用module_afromlang.test_import.module_aimportaa['value']=a['value']+1print(f'a={a}inmodule_b')module_c1和module_c2使用相对路径和绝对路径导入module_a,再导入module_b,会得到不同的结果:frommodule_aimportaimimportmodule_bprint(f'a={a}inmodule_c1')a={'value':15}inmodule_aa={'value':15}inmodule_aa={'value':16}inmodule_ba={'value':15}inmodule_c1fromlang.test_import.module_aimportaimimportmodule_bprint(f'a={a}inmodule_c2')a={'value':15}inmodule_aa={'value':16}inmodule_ba={'value':16}inmodule_c2可以看出,在module_c1中,module_a被引入了两次,分别是被认为是一个不同的模块,所以也引入了Tw添加了o变量a,c1模块只识别自己引入的相对路径命名空间中的a,所以这里的a.value并没有被模块b改变。上面的语句中,关键的错误是:将同路径下的绝对路径当成了相对路径,真正的相对路径import必须以.开头。或者..,而上面写成frommodule_aimporta的形式是因为直接运行python文件时,解释器找不到根包环境,只能以自己为根;如果被其他模块导入,则根据该模块的根判断命名空间;如果一定要基于main方法运行,可以强制指定包:__package__=lang.test_importfrom.module_aimportaimimportmodule_bprint(f'a={a}inmodule_c1')此时输出结果与theabsolutepath:a={'value':15}inmodule_aa={'value':16}inmodule_ba={'value':16}inmodule_c2关于导入和相对路径的含义和解释,最清晰的中文文档我看过的是这个:Python模块详解梳理(四),相对导入错误最优雅的解决方法
