如果从不同路径导入,则重新导入模块
在我正在工作的一个大型应用程序中,几个人以不同的方式导入相同的模块,例如 导入x 或者 从 y 导入 x 其副作用是 x 被导入两次,并且可能会引入非常微妙的错误,如果有人依赖全局属性,
例如假设我有一个包 mypakcage,其中包含三个文件 mymodule.py、main.py 和 init.py
mymodule.py 内容
l = []
class A(object): pass
main.py 内容
def add(x):
from mypackage import mymodule
mymodule.l.append(x)
print "updated list",mymodule.l
def get():
import mymodule
return mymodule.l
add(1)
print "lets check",get()
add(1)
print "lets check again",get()
它会打印,
updated list [1]
lets check []
updated list [1, 1]
lets check again []
因为现在有两个列表在两个不同的模块中,同样A类是不同的 对我来说,这看起来很严重,因为班级本身会受到不同的对待 例如,下面的代码打印 False
def create():
from mypackage import mymodule
return mymodule.A()
def check(a):
import mymodule
return isinstance(a, mymodule.A)
print check(create())
问题:
有什么方法可以避免这种情况吗?除了强制该模块只能以一种方式导入之外。这不能通过 python 导入机制来处理吗,我在 django 代码和其他地方也看到了几个与此相关的错误。
In a big application I am working, several people import same modules differently e.g.
import x
or
from y import x
the side effects of that is x is imported twice and may introduce very subtle bugs, if someone is relying on global attributes
e.g. suppose I have a package mypakcage with three file mymodule.py, main.py and init.py
mymodule.py contents
l = []
class A(object): pass
main.py contents
def add(x):
from mypackage import mymodule
mymodule.l.append(x)
print "updated list",mymodule.l
def get():
import mymodule
return mymodule.l
add(1)
print "lets check",get()
add(1)
print "lets check again",get()
it prints
updated list [1]
lets check []
updated list [1, 1]
lets check again []
because now there are two lists in two different modules, similarly class A is different
To me it looks serious enough because classes itself will be treated differently
e.g. below code prints False
def create():
from mypackage import mymodule
return mymodule.A()
def check(a):
import mymodule
return isinstance(a, mymodule.A)
print check(create())
Question:
Is there any way to avoid this? except enforcing that module should be imported one way onyl. Can't this be handled by python import mechanism, I have seen several bugs related to this in django code and elsewhere too.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
每个模块命名空间仅导入一次。问题是,您以不同的方式导入它们。第一个是从全局包导入,第二个是本地非打包
导入
。 Python 认为模块是不同的。第一个导入在内部缓存为mypackage.mymodule
,第二个导入仅缓存为mymodule
。解决此问题的一种方法是始终使用绝对导入。也就是说,始终为您的模块提供从顶级包开始的绝对导入路径:
请记住,您的入口点(您运行的文件
main.py
)也应该外部 包裹。当您希望入口点代码位于包内时,通常您可以使用运行一个小脚本来代替。示例:runme.py
,在包外:在
main.py
中添加:我找到Jp Calderone 的这份文档是关于如何(不)构建 Python 项目的一个很好的提示。遵循它,你不会有任何问题。请注意
bin
文件夹 - 它位于包外部。我将在这里重现全文:Each module namespace is imported only once. Issue is, you're importing them differently. On the first you're importing from the global package, and on the second you're doing a local, non-packaged
import
. Python sees modules as different. The first import is internally cached asmypackage.mymodule
and the second one asmymodule
only.A way to solve this is to always use absolute imports. That is, always give your module absolute import paths from the top-level package onwards:
Remember that your entry point (the file you run,
main.py
) also should be outside the package. When you want the entry point code to be inside the package, usually you use a run a small script instead. Example:runme.py
, outside the package:And in
main.py
you add:I find this document by Jp Calderone to be a great tip on how to (not) structure your python project. Following it you won't have issues. Pay attention to the
bin
folder - it is outside the package. I'll reproduce the entire text here:仅当 main.py 是您实际运行的文件时,我才能复制此内容。在这种情况下,您将获得 sys 路径上 main.py 的当前目录。但您显然还设置了系统路径,以便可以导入 mypackage。
在这种情况下,Python 将不会意识到 mymodule 和 mypackage.mymodule 是同一个模块,并且您会得到这种效果。这个变化说明了这一点:
但是在当前目录中添加另一个主文件:
结果是不同的:
所以我怀疑你的主 python 文件在包中。在这种情况下,解决方案就是不这样做。 :-)
I can only replicate this if main.py is the file you are actually running. In that case you will get the current directory of main.py on the sys path. But you apparently also have a system path set so that mypackage can be imported.
Python will in that situation not realize that mymodule and mypackage.mymodule is the same module, and you get this effect. This change illustrates this:
But add another mainfile, in the currect directory:
and the result is different:
So I suspect that you have your main python file within the package. And in that case the solution is to not do that. :-)