前言

在我们平常工程里使用Python的过程中,经常需要解决各个模块的导入问题,而且也常常遇到引用路径查找不到、交叉导入模块等等问题,故写这篇文章,旨在讲述Python的模块导入机制和我们平时大型项目中应该遵循的模块导入规范

Python模块导入

日常编程中,为了能够复用写过的代码逻辑,我们都会把这些代码封装成为模块,需要用到的时候可以直接导入复用,以便提高我们的开发效率。 module能定义函数、类、变量,也能包含可执行的代码。module来源有3种: ①Python内置的模块(标准库); ②第三方模块; ③自定义模块;

导入原理

模块的导入一般是在文件头使用import关键字,import一个模块相当于先执行了一次这个被导入模块,然后在本命名空间建立一个与被导入模块命名空间的联系,相当于在本命名空间新建了一个变量,这个变量名称是被导入模块的名称,指向被导入模块的命名空间。所以导入的这个模块相当于一个变量,因此多次导入同一个模块只有第一次导入的时候会被执行(后续导入会判断到这个模块变量已存在所以不执行)

路径查找机制

每一个导入的模块都会在Python内置字典sys.modules中,Python一启动,它将被加载在内存中,当我们导入新modules,sys.modules将自动记录下该module。 Python的模块查找路径的机制是: 1. 查找sys.path中的所有路径下是否有该模块,有则开辟新空间加载该模块; 2. 查看sys.modules中是否有内置包或已安装的第三方包,有则开辟新空间加载该模块;

所以对于我们自己编写的模块,如果封装并发布到了PyPi,则可以用pip install直接安装,并在启动时加载在内存中,通过sys.modules可以查看到 而对于仅需要在本项目中复用的模块,我们在复用代码中将其路径加入到sys.path中,同样可以引用到该模块。

绝对路径导入

所有的模块import都从“根节点”开始。根节点的位置由sys.path中的路径决定,项目的根目录一般自动在sys.path中。如果希望程序能处处执行,需手动修改sys.path

import sys,os
BASE_DIR = os.path.dirname(os.path.abspath(__file__))#项目根目录所在的绝对路径sys.path.append(BASE_DIR)import A, B #导入A、B包

相对路径导入

只关心相对自己当前目录的模块位置就好。不能在包(package)的内部直接执行(会报错)。不管根节点在哪儿,包内的模块相对位置都是正确的。

#from . import b2 #这种导入方式会报错,只有在包内部直接执行的时候才可以这样导入。
import b2#正确
b2.print_b2()

Python模块导入常见问题

  • 单独import某个包名称时,不会导入该包中所包含的所有子模块 解决办法:导入的包中也包含了其他包的导入,此时需要在每个包的init.py文件中导入该包下的所有模块,最上层才可以直接引用最下层的包的类和方法

init文件

当一个文件夹下有init.py时,意为该文件夹是一个包(package),其下的多个模块(module)构成一个整体,而这些模块(module)都可通过同一个包(package)导入其他代码中。 其中init.py文件 用于组织包(package),方便管理各个模块之间的引用、控制着包的导入行为。

该文件可以什么内容都不写,即为空文件(为空时,仅仅用import [该包]形式 是什么也做不了的),存在即可,相当于一个标记。

在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包会报错

all变量

all 是一个重要的变量,用来指定此包(package)被import *时,哪些模块(module)会被import进【当前作用域中】。不在all列表中的模块不会被其他程序引用。可以重写all,如 all= [‘当前所属包模块1名字’, ‘模块1名字’],如果写了这个,则会按列表中的模块名进行导入

name变量

在包内部直接运行时,包的name == 'main',但是在外部导入包是,可以通过

if __name__ == '__main__':

来避免实现包内部调试时的逻辑

循环导入

当两个模块A和B之间相互import时,就会出现循环导入的问题,此时程序运行会报错:can not import name xxx,如:

# a.py
print('from a.py')
from b import xy = 'a'
# b.py
print('from b.py')
from a import yx = 'b'

我们来分析一下这种错误是怎么出现的: 1. 在sys.modules中查找 符号“module b”; 2. 如果符号“module b”存在,则获得符号“module b”对应的module对象; 从的dict中获得 符号“x”对应的对象。如果“x”不存在,则抛出异常“ImportError: cannot import name ‘x’” 3. 如果符号“module b”不存在,则创建一个新的 module对象。不过此时该新module对象的dict为空。然后执行module b.py文件中的语句,填充的dict

因此在a.py中执行from b import x的顺序就是1->3,先引入b,b里面from a import y由相当于执行了a.py,顺序是1->2,因为此时b已经引入所以不会执行3,2中无法找到x对象,因为引入b时还没执行到x='b'这一步,所以报错了

解决办法

  1. 延迟导入,把import语句写在方法/函数里,将它的作用域限制在局部;
  2. 顶层先引入模块,再把from x import y改成import x.y形式;
  3. 其实出现循环引用问题的根本原因是程序设计不合理,每个包都应该由上层使用的模块去导入,而不应该在包与包之间各种相互导入,所以应该更改代码布局,可合并或分离竞争资源;

大型项目中Python模块导入规范

  1. 分离模块,将同一类别的模块放在同一目录下,形成类别分明的目录架构,如:
  1. 每一个模块目录都要写init.py文件,可以同时定义all限定可导入的范围;
  2. 源码根目录可以定义BASE_DIR,限定好根目录路径,启动py文件可以用绝对路径导入各个模块,将必要模块都加入到sys.path中;
  3. 各个服务之间(例如model需要引入common的模块方法),可以通过相对路径引用模块;
  4. 程序设计时避免循环导入,可由调用者(服务文件)作为上层第三方引入需要的各个模块,这样就可以减少各个模块的相互导入。

参考文献

  1. https://www.cnblogs.com/Zzbj/p/9607462.html
  2. https://cloud.tencent.com/developer/article/1513705
  3. https://blog.csdn.net/weixin_38256474/article/details/81228492

python导入同一文件夹下的类_Python模块导入机制与规范相关推荐

  1. python导入同一文件夹下的类_python自定义模块

    模块的引入方式: 1.import 模块名:导入模块中的所有内容(引入多个用逗号分隔) import random,time 2.from 模块名 import 函数名1,函数名2... 导入部分模块 ...

  2. Python列出文件夹下某类文件名的方法

    Python 列出文件夹下某类文件后缀 读某个文件夹下所有图片 利用os.listdir()和string.endswith()函数实现. 在进行视觉相关任务编程时, 常常需要读出文件夹下的图片.但有 ...

  3. 解决python导入当前文件夹下的包时可以运行,但编辑器报错

    比如导入当前文件夹下的config.py文件,使用: form ..config import xxx 其中..表示当前文件夹,在写代码时直接:from config import xx是不会报错的, ...

  4. python下载文件到指定目录-Python获取指定文件夹下的文件名的方法

    本文采用os.walk()和os.listdir()两种方法,获取指定文件夹下的文件名. 一.os.walk() 模块os中的walk()函数可以遍历文件夹下所有的文件. os.walk(top, t ...

  5. python怎么读文件夹下的文件夹-python如何获取当前文件夹下所有文件名详解

    前言 本文主要给大家介绍了关于python获取当前文件夹下所有文件名的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧 os 模块下有两个函数: os.walk() os.li ...

  6. python删除指定文件夹下文件和文件夹的方法

    python删除指定文件夹下的文件,是一个常用的功能.我找了不少地方,一直没有找到合适的模版,那只好自己倒腾一个比较实用的模版了. 基本模块 这里面会用到几个模块,一个是目录下所有文件的的函数:lis ...

  7. python读取文件夹下所有文件名_python如何获取当前文件夹下所有文件名详解

    前言 本文主要给大家介绍了关于python获取当前文件夹下所有文件名的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧 os 模块下有两个函数: os.walk() os.li ...

  8. python 图像格式转换文件夹下 jpg 转 bmp | 目录遍历

    python 图像格式转换文件夹下 jpg 转 bmp import os from PIL import Imagedef jpgToBmp(imgFile):dst_dir = "/ho ...

  9. Python 递归检测文件夹下的文件

    Python 递归检测文件夹下的文件. 怕自己忘记记录一下: import os# 查找指定文件夹下所有相同名称的文件 def search_file(dirPath, fileName):dirs ...

最新文章

  1. Android:手把手教你 实现Activity 与 Fragment 相互通信(含Demo)
  2. linux调用python函数,python脚本里执行linux命令的时候如何调用python的函数?
  3. netbeans7.4_NetBeans 7.2引入了TestNG
  4. Python3 正则相关
  5. C/C++—— #include“stdafx.h”详解
  6. 六、spring之通过FactoryBean为ioc容器中添加组件
  7. php数组的用法,PHP array_udiff_uassoc() 函数
  8. 在UWP的XAML中使用原始类型
  9. go interface类型转换_Go语言的九大核心特性主要有哪些?
  10. accp8.0 网页编程_某程序员月入上万!为何却说:我希望自己从来没有学过编程? - C/C++爱好者...
  11. 如何把一个运行完好的Kafka搞崩
  12. mysql 导入导出 备份_MySQL - 数据备份与还原(导出导入)
  13. matlab调用摄像头人脸识别,matlab-调用摄像头人脸识别
  14. 网络是怎样联通的-整体架构
  15. 全球最好听、最值得听的100首英文歌曲。(每首都有下载地址)
  16. 机房电脑怎么批量修改计算机名,批量设置IP地址和计算机名
  17. MAC显示屏的网页图片兼容方案
  18. 如何用随机森林算法,在深海养肥一群鱼
  19. 计算机组成原理——微程序实验
  20. connect 连接超时

热门文章

  1. linux新手常用命令
  2. 构建Docker镜像指南,含实战案例
  3. shell变量$$,$!,$?,$*,$0,$1,$#,$@的含义解释
  4. 【Python】实现最大最小距离算法
  5. PHPStorm开启Debug
  6. 记录一次可能的order by注入
  7. macos必做的设置_如何在MacOS上设置PHP,CaddyServer和Kirby —以及为什么要这样做
  8. 用python可以画的可爱的图形_利用Python绘制诱人的桑基图
  9. angular.js入门基础(一)
  10. Flink JDBC Connector:Flink 与数据库集成最佳实践