防忘系列…
Pycharm并没有IDEA一样可以设置对import进行排序以及自动消除没用到的库(要用快捷键Ctrl + Alt + O), 并且如果导入方式不正确会 1.找不到自定义包 2.Pycharm对指定内容报错(下划线或红线)
Python中模块,包,库概念
模块:就是.py文件,里面定义了一些函数和变量,需要的时候就可以导入这些模块。
包:在模块之上的概念,为了方便管理而将文件进行打包。包目录下第一个文件便是__init__.py
,然后是一些模块文件和子目录,假如子目录中也有__init__.py
,那么它就是这个包的子包了。
库:具有相关功能模块、包的集合。这也是Python的一大特色之一,即具有强大的标准库、第三方库以及自定义模块。
标准库:就是下载安装的python里那些自带的模块,要注意的是,里面有一些模块是看不到的比如像sys模块,这与linux下的cd命令看不到是一样的情况。
第三方库:就是由其他的第三方机构,发布的具有特定功能的模块。
自定义模块:用户自己可以自行编写模块,然后使用。
总结: 我们pip install <package>
安装的是库,库下有很多包,我们在自己的项目文件中import有以下几种用法:
- import numpy as np
- import urllib.parse import urlencode
- from lxml import HTML
之前大家应该碰到过,命名自己pip install xx
安装的是叫xx的库,但是在用的时候写的却是from yy import zz
,明显不对应嘛。因此,其实库和包的区别还可以通过setup.py
打包成库来看。——使用setup.py打包python文件; Python实现打包成库供别的模块调用
其中比较重要的就是5.编写:setup.py,
注意:setup.py与要打包的test_package包同在bricewulib根目录下。
其中比较重要的几项是:name,version,packages
- name:描述的是你打包的文件夹名。
- version描述的是文件的版本号。
- packages是所有要打包的包(package),这里需要打包的是test_package包以及test_package包下的test_package。输入
python setup.py sdist
然后就能创建bricewulib库,使用test_package包
1 | setup( |
import推荐顺序
我们推荐所有的模块在 Python 模块的开头部分导入。 而且最好按照这样的顺序:
- Python 标准库模块
- Python 第三方模块
- 应用程序自定义模块
通过空行来分割——(Python’s Style Guide), PEP8 。
import的搜索顺序:
- 首先判断这个module是不是built-in即内建模块,如果是则引入内建模块,如果不是则在一个称为sys.path的list中寻找
- sys.path在python脚本执行时动态生成,包括以下3个部分:
- 脚本执行的位置,即当前路径
- 环境变量中的PYTHONPATH, 即.bash_profilec.
- 安装python时的依赖位置
Python的import机制
运行、编写Python代码时,一定要注意的是脚本路径和脚本执行路径,以及相对路径和绝对路径
如果在项目中运用了相对路径,则一定要注意脚本执行路径
假设A是B的父目录, 如我们想在A目录调用B中模块, 而B中模板是又import了A下模板, 如login: from login import ftSession
。命令行在A路径下输入python B/main.py
时, 会报错。因为import其实就是在搜索目录下按相对路径找的。
Pycharm的坑:
pycharm里打出来的路径是更多的,它把项目根目录加进去了。(也可以设置: 进入设置,找到Console下的Python Console,勾选选项**“Add source roots to PYTHONPAT”** )
查看搜索路径:print(sys.path)
What’s resource root?
以上导致的问题就是:
pycharm中,project folder是默认的source root,当你使用import语句导入模块时,Pycharm默认在project folder中寻找;所以当你在project folder下的某个subfolder导入某个同样定义在这个subfolder中的模块时,会出现导入错误。
pycharm中的第一个文件夹,即代表项目, 当在其中再次建立文件夹时,是按package处理的
如果要在这些文件夹内import其他文件,需要将完整路径导入进来
所以最终在Pycharm中导入的方式有两种: burning回答
- 从project folder开始相对导入
- 将module文件夹直接定义为source root
pycharm在同目录下import划红线但实际可以运行
解决方法: 右键将model所在的文件夹设置为source root
总结:python该如何import
需要明确的一点是:在运行Python脚本的时候,Python解释器会把脚本执行的位置,即当前路径加入到搜索路径中,而绝大多数情况main函数就在工程根目录,因此对于一个工程而言,最好的是从从project folder(工程根目录,即运行main函数的那个入口文件)开始相对导入
举个栗子:
1 | G:. |
在这里ai/utils中mct.py需要import board.py中的Board对象等,mct.py中import具体写法为
1 | from enum import Enum |
▲需要注意的是,对于main函数如果不在根目录,而是在工程目录的子目录中的情况,需要在main.py中自己手动添加sys.path.append("..")
,即想办法把工程根目录加到搜索目录中,这样以后就可以又开始从工程根目录开始import了。
还有一个对于初学者可能会产生自我怀疑的点,我也顺便提一下好了
1 | from config import * |
__init__
文件作用
在Python工程里,当python检测到一个目录下存在__init__.py
文件时,python就会把这个目录当成一个包(package)。Module跟C++的命名空间和Java的Package的概念很像,都是为了科学地组织化工程,管理命名空间。
__init__.py
的设计原则
__init__.py
的原始使命是声明一个模块,所以它可以是一个空文件。
A、不要污染现有的命名空间。模块一个目的,是为了避免命名冲突,如果你在种用__init__.py时违背这个原则,是反其道而为之,就没有必要使用模块了。
B、利用__init__.py
对外提供类型、变量和接口,对用户隐藏各个子模块的实现。一个模块的实现可能非常复杂,你需要用很多个文件,甚至很多子模块来实现,但用户可能只需要知道一个类型和接口。就像我们的arithmetic例子中,用户只需要知道四则运算有add、sub、mul、dev四个接口,却并不需要知道它们是怎么实现的,也不想去了解arithmetic中是如何组织各个子模块的。由于各个子模块的实现有可能非常复杂,而对外提供的类型和接口有可能非常的简单,我们就可以通过这个方式来对用户隐藏实现,同时提供非常方便的使用。
C、只在__init__.py中导入有必要的内容,不要做没必要的运算。像我们的例子,import arithmetic语句会执行__ini__.py
中的所有代码。如果我们在__init__.py
中做太多事情,每次import都会有额外的运算,会造成没有必要的开销。一句话,init.py只是为了达到B中所表述的目的,其它事情就不要做啦。
上述来自: https://zhuanlan.zhihu.com/p/115350758
__all__
变量
__all__
是一个字符串list;
约束作用:用来定义模块中对于from XXX import *
时要对外导出的符号,即要暴露的借口,但它只对import *
起作用(即如果在使用脚本中对当前包使用import *,那么可以管理当前包下模块的导入情况),对from XXX import XXX
不起作用。
Author: Mrli
Link: https://nymrli.top/2020/10/23/Python中import的细节/
Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.