Python 2.7升级至3.6后相对导入不一致问题咨询
嘿,我来帮你理清楚这个问题——其实你遇到的差异不是Python3相对导入语法的锅,而是你修改导入语句的时候,不小心改变了导入的类型,导致代码里的命名空间内容不一样了!
先拆解两个场景的差异
dev.py的修改能正常运行:
原来的from base import *和修改后的from .base import *,本质都是把base模块里的所有公开成员(非下划线开头的名字)直接导入到dev.py的命名空间里,两者的效果完全一致,只是Python3要求同包内的相对导入必须加.,所以这个修改没问题。urls.py修改后报错的原因:
你原来的代码是from . import views——这个语句是把整个views模块对象导入到urls.py的命名空间里,所以之后你可以用views.xxx(比如views.home)来访问模块里的内容;但你改成from .views import *之后,是把views模块里的所有公开成员直接导入到urls.py的命名空间里,而没有导入views这个模块对象本身。这就导致如果你的urls.py里还有直接引用views这个模块名的代码(比如urlpatterns里的path('home', views.home)),自然就会报NameError——因为当前命名空间里根本没有views这个名字!
怎么让代码保持一致又解决问题?
有两种方案可以选,看你想统一哪种风格:
方案1:统一导入模块对象的风格
如果你想继续保留views.xxx这种调用方式(和原来的代码逻辑一致),那完全可以继续用from . import views这个写法——它是Python3完全认可的相对导入语法,根本不需要改成from .views import *。这样既符合Python3的规范,又能保持代码原来的运行逻辑,不会报错。
方案2:统一导入模块成员的风格
如果你确实想把所有导入都改成from .[module] import *的形式,那你需要把代码里所有用到views.xxx的地方,直接改成xxx(因为这些成员已经被导入到当前命名空间了)。比如原来的:
path('home/', views.home)
要改成:
path('home/', home)
额外提醒:Python3相对导入的核心逻辑
再给你补个小知识点,避免以后踩坑:
- 所有以
.开头的导入都是相对导入:.代表当前包,..代表父包,以此类推; from . import module→ 导入整个模块对象到当前命名空间;from .module import name/from .module import *→ 导入模块里的具体成员到当前命名空间,不会导入模块对象本身;- 你这次的问题本质是混淆了这两种导入方式的命名空间差异,和Python2→3的语法变更本身无关,只是修改时误改了导入类型。
内容的提问来源于stack exchange,提问作者ravioli

