python import 导入

发布于 2024-12-15 17:53:55 字数 8624 浏览 24 评论 0

一个关于 import 的经典引论

Imports are pretty straightforward really. Just remember the following:

import and from xxx import yyy are executable statements. They execute when the running program reaches that line.

If a module is not in sys.modules , then an import creates the new module entry in sys.modules and then executes the code in the module. It does not return control to the calling module until the execution has completed.

If a module does exist in sys.modules then an import simply returns that module whether or not it has completed executing . That is the reason why cyclic imports may return modules which appear to be partly empty.

Finally, the executing script runs in a module named __main__ , importing the script under its own name will create a new module unrelated to __main__ .

Take that lot together and you shouldn't get any surprises when importing modules.

python 结构

python-modules-packages : python 的模块化编程(modular programming) 主要包括了两个较为重要的概念 modules 以及 packages ,模块化编号的目的是将大而复杂的代码切分成多个小而简单的代码,是代码的迭代和维护更加简单,模块编程的优点有:

  • 简单的: 可以编写简单的函数而不是针对庞大的复杂问题
  • 易于维护的: 因为函数是简单的,可以更好的写测试来维护代码的功能
  • 可重复使用的: 其他程序可以将简单的调用模块中的程序,因为他是一个比较抽象的功能而不是具体的实现
  • 更加有范围的: 可以使得类 函数 变量更加有范围

modules

定义了 python 一些成员的文件

packages

理解 import 的前提

  • import 的工作流程, 拿 import abc 作为说明
    • The first thing Python will do is look up the name abc in sys.modules . This is a cache of all modules that have been previously imported.
    • If the name isn’t found in the module cache
      • Python will proceed to search through a list of built-in modules. These are modules that come pre-installed with Python and can be found in the Python Standard Library .
      • If the name still isn’t found in the built-in modules, Python then searches for it in a list of directories defined by sys.path . This list usually includes the current directory, which is searched first.
    • When Python finds the module, it binds it to a name in the local scope. This means that abc is now defined and can be used in the current file without throwing a NameError .
  • 如何引用: 引用模块使用 import module_namefrom module_name import module_element 两条语句都是可行的
  • 引用的结果: 引用了模块后, sys.modules 里记录了当前 run time 下所有已经导出的 module, 也就是说在我们使用 import 的时候,python 会先去 sys.modules 查看将要被引用的模块在不在里面
  • 判断一个模块是否在当前的 run time 中: "module" in sys.modules
  • 如果 module_name 不在 sys.modules 中,那 import module_name 将会执行:
    • sys.modules[module_name] = [empty pyc file]
    • execute module_name to generate a module_name.pyc file
    • sys.modules[module_name] = module_name.pyc file path
  • 如果 module_name 已经在 sys.moudles 中,那会去 load 对应的 pyc file,但关键就在这里的 pyc 文件,有两种情况:
    • 上面第一步生成的 pyc 文件,大多数循环引用导致 AttributeError 错误的原因; 循环引用就会存在这样的问题 此时因为 module_name 文件还没有运行完
    • 上面第三部生成的 pyc 文件,正常情况,不会出异常.

import 的排序顺序

  • Imports should always be written at the top of the file, after any module comments and docstrings.
  • Imports should be divided according to what is being imported. There are generally three groups:
    • standard library imports (Python’s built-in modules)
    • related third party imports (modules that are installed and do not belong to the current application)
    • local application imports (modules that belong to the current application)
  • Each group of imports should be separated by a blank space.
"""Illustration of good import statement styling.

Note that the imports come after the docstring.

"""

# Standard library imports
import datetime
import os

# Third party imports
from flask import Flask
from flask_restful import Api
from flask_sqlalchemy import SQLAlchemy

# Local application imports
from local_module import local_class
from local_package import local_function

相对引用和绝对引用

相对引用

以资源当前路径为相对路径,通过相对路径引用别的资源,使用 . 区分相对引用和绝对引用 from .some_module import some_class

绝对引用

绝对引用是以当前项目的根为开始,使用全路径的引用 from package1 import module1 ,但是如果路径过长会导致引用的语句过长难以阅读

FAQ

文件名和标准库文件一样

Python ImportError: cannot import name itemgetter : 和 python 内置模块名冲突,You should rename your file to not conflict with Python's standard library.

循环导入问题(circular import 或者 cyclic import)

理解循环引用的前提

理解 import 的前提

循环引用的简单例子

例子

假设有如下的两个文件

# cat a.py
import b
print("This is from module a")

# cat b.py
import a
print("This is from module b")

当我们运行 a.py 时,由于 循环引入 会打印如下内容

'This is from module a'
'This is from module b'
'This is from module a'

它引用的过程如下:

  • The first line is import b . so it will visit module b
  • The first line at module b is import a . so it will visit module a
  • The first line at module a is import b but note that this line won't be executed again anymore , because every file in python execute an import line just for once , it does not matter where or when it is executed. so it will pass to the next line and print This is from module a .
  • After finish visiting whole module a from module b , we are still at module b. so the next line will print This is from module b
  • Module b lines are executed completely. so we will go back to module a where we started module b.
  • import b line have been executed already and won't be executed again. the next line will print This is from module a and program will be finished.

循环导入导致 AttributeError 错误

这里

假设有两个文件

# cat a.py
print "a in"
import sys
print "b imported: %s" % ("b" in sys.modules)
import b
print "a out"
print b.x

# cat b.py
print "b in"
import a
print "b out"
x = 3

运行 a.py ,参考 循环引用的简单例子 ,输出如下:

a in
b imported: False
b in
a in
b imported: True
a out
Traceback (most recent call last):
  File "a.py", line 4, in <module>
    import b
  File "/home/shlomme/tmp/x/b.py", line 2, in <module>
    import a
 File "/home/shlomme/tmp/x/a.py", line 7, in <module>
    print b.x
AttributeError: 'module' object has no attribute 'x'

这个错误的原因是在 b.py 运行 import a 时候会执行 a.py 中的全部内容,但是 b.py 还没有运行完,所以会导致 x=3 的初始化没有运行.根据 理解 import 的前提 此时的 b 存在于 sys.moudles 中,但是指向的是一个空的 pyc 文件,要等文件运行完 b 才能更新 sys.moudles 对应的值

如何避免循环导入问题

解决循环导入问题

  • 延迟导入(lazy import): 即把 import 语句写在方法或函数里面,将它的作用域限制在局部,这种方法的缺点就是会有性能问题
  • from xxx import yyy 改成 import xxx;xxx.yyy 来访问的形式,这种办法并不能解决所有场景下的问题
  • 合理组织代码: 出现循环 import 的问题往往意味着代码的布局有问题,可以 合并 或者 分离 竞争资源,将循环变成单向
    • 合并就是将循环引用的代码写到一个文件中
    • 分离就是把需要 import 的资源提取到第三方文件去

项目在 Pycharm 中运行成功,但是在 terminal 中报错 modulenotfounderror

Pycharm 在运行 python 代码(运行 python console) 的时候做了一定处理,他将项目的根目录放到了 PYTHONPATH 中,这样就能 import 没有在 site-package 的,自己写的了

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

陈年往事

暂无简介

文章
评论
28 人气
更多

推荐作者

yuanzihao09

文章 0 评论 0

1337793151

文章 0 评论 0

你在我安

文章 0 评论 0

qq_QhAHT0kB

文章 0 评论 0

aaaa123451

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文