• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

关于python:Python解决python3中关于import的疑难杂症

python 搞代码 3年前 (2022-02-20) 13次浏览 已收录 0个评论
文章目录[隐藏]

python中import与包治理

概念:模块与包

  • 模块module:个别是以.py为后缀的文件,也包含.pyo.pyc.pyd.so.dll后缀的文件,模块内定义了函数、类以及变量
  • package:包是含有若干个模块的文件夹,在工程项目用包治理模块能够防止模块名抵触

\_\_init\_\_.py

在Python工程项目中,如果一个文件夹下有__init__.py文件就会认为该文件夹是一个包package,这样能够不便组织工程文件,防止模块名抵触。

  • __init__.py为空时仅用于标识以后这个文件夹是一个包package
  • __all__变量指明当该包被import *时,哪些模块module会被导入
  • 能够利用__init__.py对外提供类型、变量及接口,对用户暗藏各个子模块的实现细节
  • 当咱们import一个包时,会主动加载该包对应的__init__.py,因而如果在其中做太简单的运算会造成不必要的开销

sys.modules

sys.modules保护了一个已加载module的字典,第二次加载该module时能够间接从字典中查找,放慢执行速度。

import sys
print(sys.modules)

// 输入:
{'random': <module 'random' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/random.pyc'>, 'subprocess': <module 'subprocess' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.pyc'>, 'sysconfig': <module 'sysconfig' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/sysconfig.pyc'>, 'gc': <module 'gc' (built-in)>}

namespace

  • local namespace:函数的命名空间,记录函数的变量
  • global namespace:模块的命名空间,记录模块的变量(函数、类、导入的模块、模块级别的变量和常量)
  • build-in namespace:蕴含build-in functionexceptions,可被任意模块拜访

import形式影响咱们应用包的形式正是namespace作用的体现:

from foo import bar  # 将模块foo中的函数/变量bar导入到以后模块的命名空间, 能够间接拜访bar
import foo  # 导入模块foo同时保留它本人的命名空间, 须要通过foo.bar的形式来拜访bar

模块外部属性

  • __doc__:文件正文
  • __file__:以后文件门路
  • __package__:导入文件的门路
  • __cached__:导入文件的缓存门路
  • __name__:导入文件的门路加文件名称
  • __builtins__:蕴含内置函数

python内置模块

  • os:提供文件和目录等的零碎级操作
  • sys:提供对解释器相干的操作
  • hashlib:提供加密相干的操作,代替了md5sha模块
  • shutil:提供文件、文件夹和压缩包等解决模块
  • configparser:提供对特定配置的操作
  • logging:提供日志性能
  • time datetime:提供工夫相干操作
  • random:提供随机数操作
  • jsonpickle:提供序列化操作
  • shelve:提供简略kv将内存数据通过文件长久化的性能

import形式

1. 简介

在Python中import的罕用操作为:

import somemodule  # 导入整个模块
from somemodule import somefunction  # 从模块中导入单个函数
from somemodule import firstfunc, secondfunc, thirdfunc  # 从模块中导入多个函数
from somemodule import *  # 从模块中导入所有函数

2. 执行import的步骤

  1. 创立一个新的module对象
  2. 将该module对象插入sys.modules
  3. 装载module的代码
  4. 执行新的module中对应的代码

3. import的搜寻包程序

留神第三步装载module代码时python解释器须要先搜寻到对应的.py文件,搜寻程序为:

  • sys.path:蕴含了以后脚本的门路和其余查找包(零碎库、第三方库等)的门路,你也能够在代码中通过sys.path.append()动静增加搜寻门路
  • PYTHONPATH
  • 查看默认门路,比方Linux下为/usr/local/lib/python/

4. 相对导入与绝对导入

相对导入和绝对导入的概念只针对于包内模块导入包内模块,留神如果foo.pybar.py在同一个非包(没有__init__.py文件)的目录下,那么它们之间能够相互import,不存在相对导入和绝对导入的问题。

在Python3中倡议应用相对导入。

举个例子:

<code class="bash">$ tree
mypackage
├── __init__.py
├── module_bar.py
└── module_foo.py

在包mypackage内,如果module_bar要导入module_foo,那么有三种形式:

# 办法一: 
import module_foo

# 办法二:
# 如果是下层文件夹写.., 上下层文件夹写..., 以此类推
from . import module_foo

# 办法三:
from mypackage import module_foo
import mypackage.module_foo
  • 对于python2而言,办法一和办法二都是绝对导入,成果一样,然而前者被称为隐式绝对导入,后者被称为显式绝对导入,办法三是相对导入(会在sys.path中的门路搜寻)
  • 对于python3而言,办法二是绝对导入,办法一和办法三都是相对导入,官网更举荐办法三

5. 包导入

包的导入和模块导入基本一致,只不过导入包时会执行__init__.py。如果只是导入一个包import package而不指名任何模块,且包中的__init__.py没有其余的初始化操作,那么包上面的模块是无奈被主动导入的。

6. 间接运行与模块运行

以上面的我的项目为例:

$ tree
.
└── mypackage
    ├── __init__.py
    └── module_foo.py
    
# module_foo.py内容如下:
import sys
print(sys.path)

咱们有两种形式运行module_foo.py

-m参数示意run library module as a script,即以脚本的形式执行模块。

<code class="bash"># 间接运行: 第一个目录是模块module_foo所在的
$ python3 -B mypackage/module_foo.py    
['/Users/didi/Desktop/MyProject/mypackage', '/Library/Frameworks/Python.framework/Versions/3.7/lib/python37.zip', '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7', '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/lib-dynload', '/Users/didi/Library/Python/3.7/lib/python/site-packages', '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages']

# 模块运行: 第一个目录是以后门路
$ python3 -B -m mypackage.module_foo
['/Users/didi/Desktop/MyProject', '/Library/Frameworks/Python.framework/Versions/3.7/lib/python37.zip', '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7', '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/lib-dynload', '/Users/didi/Library/Python/3.7/lib/python/site-packages', '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages']

实例:包之间模块援用的疑难杂症

1. 我的项目demo

假如以后你的工程文件目录如下(仅针对python3):

留神这里我的文件夹下并没有__init__.py,严格来讲它们并不是包,只是将分割严密的模块放在同一个文件夹下不便工程项目管理。

<code class="bash">.
└── src
    ├── bar_package
    │   └── module_1.py
    ├── foo_package
    │   ├── module_2.py
    │   └── module_3.py
    └── main.py
# 留神
# 1) 所有模块都以src为根目录, 包含main.py(当然这只是我集体习惯)
# 2) 引入形式都是相对引入(python3举荐应用)

"""
module_1.py: 空文件
"""

"""
module_2.py: import同个包内的module_3
"""
from foo_package import module_3  # 援用同个包的模块

"""
module_3.py: import另一个包内的module_1
"""
from bar_package import module_1  # 跨包援用模块

if __name__ == "__main__":
    print("module_3 exec successfully!")

"""
main.py: import所有模块
"""
from foo_package import module_3, module_2
from bar_package import module_1

下面就是通常我的项目文件包治理的形式,执行整个程序:

<code class="bash">python3 -B src/main.py

2. 问题:独自执行某个模块

如果要独自执行module_3.py,这时候会报错:

<code class="bash">$ python3 -B src/foo_package/module_3.py 
Traceback (most recent call last):
  File "src/foo_package/module_3.py", line 1, in <module>
    from bar_package import module_1  # 跨包援用模块
ModuleNotFoundError: No module named 'bar_package'

回顾一下之前提到的import查找包的门路,咱们有两种办法能够解决这个问题。

3. 办法一:通过模块运行的形式解决(举荐)

实质上咱们是心愿将module_3.py这个模块作为脚本运行,所以咱们能够带上-m参数:

<code class="bash">$ cd src  # 代码中是以src为根目录的, 所以须要进入到src下
$ python3 -B -m foo_package.module_3   
module_3 exec successfully!

4. 办法二:在sys.path中增加查找门路

后面的报错是找不到bar_package的模块名,因为间接运行的话sys.path第一个门路就是module_3.py的门路,天然找不到它下层的bar_package,咱们能够通过sys.path.append(..)将它的下层目录也退出sys.path,批改后的module_3.py文件内容为:

"""module_3.py
实质上就是将module_3.py的下级目录退出到sys.path中, 这样就能够找到bar_package了
"""
import os
import sys
parent_path = os.path.dirname(sys.path[0])
if parent_path not in sys.path:
    sys.path.append(parent_path)
from bar_package import module_1  # 跨包援用模块


if __name__ == "__main__":
    print("module_3 exec successfully!")

须要留神的是,如果你应用的是如下这种写法还是可能呈现问题:

"""module_3.py
"""
import sys
sys.path.append("../")
from bar_package import module_1  # 跨包援用模块


if __name__ == "__main__":
    print("module_3 exec successfully!")

# 进入到module_3.py所在的目录, 输入失常:
$ src/foo_package 
$ python3 -B module_3.py 
module_3 exec successfully!

# 间接在根目录下执行会报错:
$ python3 -B src/foo_package/module_3.py
Traceback (most recent call last):
  File "src/foo_package/module_3.py", line 3, in <module>
    from bar_package import module_1  # 跨包援用模块
ModuleNotFoundError: No module named 'bar_package'

另一种简洁的写法是:

import sys
import oss
sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))

5. 尽量不要应用绝对援用

Python3不倡议应用绝对援用,最好遵循肯定的开发标准,不要在代码中混用相对援用与绝对援用。

Reference

[1] https://www.gaodaima.com/weixin_&#8230;

[2] https://zhuanlan.zhihu.com/p/&#8230;

[3] https://www.cnblogs.com/schip&#8230;

[4] https://www.gaodaima.com/p/88b&#8230;


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:关于python:Python解决python3中关于import的疑难杂症

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址