Python:为什么导入包有时会授予对其下模块的访问权限,但有时却不会?

标签 python python-import

Python 导入机制对我来说一直是一个神话。有时导入一个包可以授予对其下面模块的访问权限。例如,

import urllib
urllib.parse.unquote

给予

<function urllib.parse.unquote>

这表明即使只导入了包(即本例中的 urllib)也可以访问函数,但不能访问模块文件。这是在 Jupyter Notebook 中完成的。

但是当我在终端做同样的事情时

>>> import urllib
>>> urllib.parse.unquote
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'urllib' has no attribute 'parse'

两个 Python 版本都是 3.6.1。

有什么不同,什么是好的做法?

编辑以合并@user2357112 和@Tomoki 的答案。

直接来自@user2357112

For an access to urllib.parse to work, the following two conditions must be true:

The urllib module object must be bound to the urllib name, whether in the local, global, or some enclosing scope. The urllib.parse submodule must have been initialized and bound to the parse attribute of the urllib module object. An import urllib in the current local or global scope (or any enclosing scope) satisfies the first condition.

An import urllib.parse executed anywhere in the program satisfies the second condition, since it loads the submodule and binds it to the parse attribute on the urllib module object, and there's only one urllib module object for the whole program.

In the environments where urllib.parse was accessible after a simple import urllib, some other code must have loaded urllib.parse, causing you to see it.

证据由@Tomoki提供

Test: "import IPython"
 └─IPython:┐
      ┌────┘
      ├──"from core.application import Application"
      │   └──IPython.core.application: "from IPython.core import release, crashhandler"
      │      └──IPython.core.crashhandler: "from IPython.core import ultratb"
      │         └──IPython.core.ultratb: "import pydoc"
      │            └──pydoc: "import urllib.parse"
      └──"from terminal.embed import embed"
          └──IPython.terminal.embed:┐
                        ┌───────────┘
                        ├──"from IPython.core import magic_arguments"
                        │   └──IPython.core.magic_arguments: "from IPython.utils.text import dedent"
                        │      └──IPython.utils.text: "from pathlib import Path"
                        │         └──pathlib: "from urllib.parse import quote_from_bytes"
                        ├──"from IPython.core.magic import Magics, magics_class, line_magic"
                        │   └──IPython.core.magic: "from IPython.core import oinspect"
                        │      └──IPython.core.oinspect: "from IPython.core import page"
                        │         └──IPython.core.page: "from IPython.core.display import display"
                        │            └──IPython.core.display: "import mimetypes"
                        │               └──mimetypes: "import urllib.parse"
                        └──"from IPython.terminal.interactiveshell import TerminalInteractiveShell"
                            └──pygments.plugin: "import pkg_resources"
                               └──pkg_resources: "import email.parser"
                                  └──email.parser: "from email.feedparser import FeedParser, BytesFeedParser"
                                     └──email.feedparser: "from email._policybase import compat32"
                                        └──email._policybase: "from email.utils import _has_surrogates"
                                           └──email.utils: "import urllib.parse"

最后一行确实涉及 urllib.parse

另一个证据

import scipy 不提供在终端或 Jupyter notebook 中对 scipy.stats.norm 的访问,因为没有任何环境接触到 scipy.stats

什么是好的做法?

从上面我们可以得出结论,##import the whole module levels## 不仅是一个好的做法,而且实际上是一个要求。

“始终导入到文件(模块)级别以保证访问”

谢谢大家的回答!

最佳答案

要访问 urllib.parse 才能正常工作,必须满足以下两个条件:

  1. urllib 模块对象必须绑定(bind)到 urllib 名称,无论是在本地、全局还是某个封闭范围内。
  2. urllib.parse 子模块必须已经初始化并绑定(bind)到 urllib 模块对象的 parse 属性。

当前本地或全局范围(或​​任何封闭范围)中的 import urllib 满足第一个条件。

import urllib.parse程序中的任何地方执行 满足第二个条件,因为它加载子模块并将其绑定(bind)到 parse urllib模块对象的属性,整个程序只有一个urllib模块对象。

在简单的 import urllib 之后可以访问 urllib.parse 的环境中,一些其他代码必须加载 urllib.parse,导致你看到它。

关于Python:为什么导入包有时会授予对其下模块的访问权限,但有时却不会?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46478864/

相关文章:

python - 从文本到字典,更新键值

python - 为什么从同一目录中的模块导入模块时必须在模块前加一个点?

python - 如何让第二个 __init__.py 执行相同的命名空间

python - 导入错误:No module named

python - AWS Lambda boto3 : Instance launch from lambda boto3 python eroor

python - 从包含许多元素的列表中删除重复项

Python optparse make_option() 相当于 argparse

python - 是否可以将 agg 和 value_counts 与 Pandas 组合在单行中

Python 覆盖 : A case for monkey Patching

python - 动态组装 Python 模块,动态导入