import语句如何修改模块的符号表?

2024-05-08 21:53:59 发布

您现在位置:Python中文网/ 问答频道 /正文

我有以下模块:

foo/
   __init__.py
   random.py

random.py只是一个空文件,__init__.py包含以下内容:

import random

def print_random():
    import foo.random
    print(random.random())

当我用python -c 'import foo; foo.print_random()'调用上述函数时,得到的是AttributeError: module 'foo.random' has no attribute 'random'。你知道吗

似乎print_random()中的import语句已将对内置模块的引用替换为对foo.random的引用。有人能解释一下为什么它没有在前面提到的表中添加新记录吗?我在哪里能读到更多关于它的资料?有没有避免这种情况的推荐做法?你知道吗

更新#1

我在Python2.7和Python3.5中都遇到了相同的错误。我注意到的唯一区别是python2的措辞略有不同:AttributeError: 'module' object has no attribute 'random'。你知道吗

print_random()中的sys.modules['random']指的是内置的随机模块,而globals()['random']指的是foo/random.py。你知道吗

import foo.random不必在print_random()中。它可以从那里删除并添加到用于运行脚本的命令中(例如python-c'import foo;import)foo.random公司; foo.print\u随机()'),这将产生相同的结果。你知道吗


Tags: 模块文件nopyimportfooinitdef
1条回答
网友
1楼 · 发布于 2024-05-08 21:53:59

这里有两种机制:

一方面,在执行import foo.random语句时,我们通常希望名称foo将绑定在本地上下文中,并且foo.random将作为foo的成员根据import语句的docs.可用

另一方面,根据子模块doc,“当使用任何机制[…]加载子模块时,会在父模块的命名空间中放置到子模块对象的绑定”。你知道吗

__init__.py文件的特殊情况下,这意味着foo.random既可以作为名称random也可以作为绑定到foo的对象的random成员,因为在__init__.py文件中,我们直接在父模块的上下文中工作(即,我们在foo上下文中工作,而不是在foo.__init__上下文中工作)。你知道吗

最好的解决方案是,如果可以避免的话,不要在__init__包中编写代码,而只使用它来公开名称、初始化记录器等。通常为要相对于父包公开的模块创建一个包以获得表达能力也是一个很好的做法,尽管它不能解决这个问题。你知道吗

总之,如果您想公开一个foo.random包,同时拥有一个foo.print_random函数和上述内容,我建议您使用以下布局:

foo/
  __init__.py
  print_random.py
  random/
    __init__.py

foo/\uuu初始化\uuuuuuuuuy.py

from foo.print_random import print_random

foo/打印_随机.py你知道吗

import random

def print_random():
    import foo.random
    print(random.random())

相关问题 更多 >