首页 > 编程语言 >python import 思考二

python import 思考二

时间:2025-01-20 14:29:18浏览次数:3  
标签:__ python py module1 导入 思考 package1 import

前言

思考一中 简单介绍了import导入模块时的检索机制

然而在实际的导入时,我们经常会导入失败,尤其是在相对导入时。

下面就绝对导入和相对导入时发生的一些问题 进行记录和思考

文件目录结构

my_project/
|-- package1/
|	|-- subpackage1/
|	|	|-- module2.py
|	|-- module1.py
|-- package2/
|	|-- subpackage2/
|	|	|-- module4.py
|	|-- module3.py
|-- __init__.py
|-- main.py
|-- module5.py

各模块定义初始内容

# package1/module1.py
def func1():
    print("This is func1 from module1 in package1")

# package1/subpackage1/module2.py
from ..module1 import func1


def func2():
    print("This is func2 from module2 in subpackage1 of package1")
    func1()

# package2/module3.py
def func3():
    print("This is func3 from module3 in package2")


# package2/module4.py
from package1.module1 import func1
from ..module3 import func3


def func4():
    print("This is func4 from module4 in subpackage2 of package2")
    func1()
    func3()

**注意: my_project 项目的运行环境为pycharm IDE 而非shell 环境 , **

my_project 设置成了内容根并加入到了PYTHONPATH (防止某些版本的解释器(嵌入式发行版)不会自动将当前目录加入sys.path中)


绝对导入

绝对导入的语法:import module/package (注意:模块/包路具体的书写方式 是相对于导入查找机制所查找到的文件路径而构造的)下面举例

例如:

  1. 系统内置包 已经内嵌在解释器中 所以无论何时何地 只需要import 包名 就行

  2. 第三方包(通过pip/其他方式安装),也是 import 包名 就行, 因为包的父目录会被解释器自动加入到sys.path路径中。

  3. 自定义的包(这里需要灵活构造), 针对当前的项目, 如果我运行main.py文件,解释器会自动将其所在的父目录加入sys.path中。所以如果我想在main 中导入 module1中的 func1 构造导入的路径就需要根据父目录 my_project 来构造,如下

    # 运行脚本: main.py
    # mian.py 代码
    import sys
    import package1.module1
    
    package1.module1.func1()
    
    print(sys.path)
    print(dir())
    print(dir(package1))
    
    
    “”“
    输出:
    
    This is func1 from module1 in package1
    ['E:\\work\\my_project', 'D:\\python\\python3.8.8\\python38.zip', 'D:\\python\\python3.8.8\\DLLs', 'D:\\python\\python3.8.8\\lib', 'D:\\python\\python3.8.8', 'E:\\work\\game\\mygame', 'E:\\work\\game\\mygame\\lib\\site-packages']
    ['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'package1', 'sys']
    ['__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'module1']
    ”“”
    
    # 因为sys.path[0]如上所说会自动加载为当前脚本的所在的父目录,所以我们导入module1时书写的方式自然要以my_project为查找起点
    # 如此构造 是告诉解释器 你去根据你的检索路径找吧, 看看有没有一个路径下会有package1/module1. 那么解释器挨个查找下来
    # 当遇到sys.path[0] 时,在它下面发现了真有一个包为package1, 又因为它是一个包,继续遍历下去,在package1包下找到了
    # module1.py, 然后就把 package1 加到了当前命名空间内, 而module1 则在package1的命名空间内。 所以你调用时也要按照
    # 导入的顺序,
    
    # 理解了上述的,那么对绝对导入的构造也就举一反三了,不过再提一点,嫌调用太长 也可以以别名的方式去优化命名。例如
    import sys
    import package1.module1 as XX
    
    XX.func1()
    
    print(sys.path)
    print(dir())
    print(dir(XX))
    
    “”“
    输出:
    
    This is func1 from module1 in package1
    ['E:\\work\\my_project', 'D:\\python\\python3.8.8\\python38.zip', 'D:\\python\\python3.8.8\\DLLs', 'D:\\python\\python3.8.8\\lib', 'D:\\python\\python3.8.8', 'E:\\work\\game\\mygame', 'E:\\work\\game\\mygame\\lib\\site-packages']
    ['XX', '__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'sys']
    ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'func1']
    ”“”
    
    
    # 别名便于书写,但有时候乱起别名 不仅做不到见文知意,反而可能会引发命名冲突,需要自己考量
    

相对导入

其实大部分的时候 能以绝对导入的方式导入包/模块,就已经可以了。但如果一个大的项目,有个地方的名称变了,那么可能需要重构所有

引用到该包的路径了,此时相对导入的优势就体现了。

相对的核心在于 :

1. 相对指的是要导入的包相对于自己的包所在的位置,即以自身为起始点 查找到要使用的包 然后导入到自己所在的命名空间内 为已所用

2. 被导入模块能以相对导入的方式被找到,而这就是相对导入时常会出错所在,有时候明明考虑到了第一点 语法正确 却报找不到的问题

下面重点阐述 核心点2

在说明问题之前,我们需要知道 对于相对 import,可以通过查看 __package__ 才能决定是否能采用这种导入模式

只有__package__值为 [XX].[grandparent_package].parent_package 这种模式才能使用相对导入,

此时相对导入中的.对应的就是parent_package, .. 对应的是 grandparent_package...对应的是XX 以此类推

值得注意的是如果当前模块即主程序入口(顶级模块)或者同级工作目录下的其他模块 是无法使用相对导入

1、当前模块为顶级模块时:解释器会自动将其所在的工作目录作为顶级目录,而不是作为一个包,此时__package__属性为None 则无法采用 相对导入

# 运行脚本: main.py
# main.py 代码1
import .module5

module5.func5()

"""
输出
  File "E:/work/my_project/main.py", line 1
    import .module5
           ^
SyntaxError: invalid syntax
"""

# main.py 代码2
print(__package__)

# 输出 None



2、此时它的同级目录下的模块的__package__属性为空,没有目录层级关系 也无法使用相对导入

# 运行脚本: main.py
# mian.py 代码
import module5

# module5.py 代码
def func5():
    print("This is func5 from module5 in my_project")

print(__name__)

"""
main.py输出

"""

能导入的情况(举例说明):

# 运行脚本: main.py
# mian.py 代码
import package1.subpackage1.module2
import package2.subpackage2.module4


package1.subpackage1.module2.func2()
package2.subpackage2.module4.func4()


#package1/subpackage1/module2py 新代码
from ..module1 import func1


def func2():
    print("This is func2 from module2 in subpackage1 of package1")
    func1()


print("module2's __package__ is %s " % __package__)


# package2/module4.py 新代码
from package1.module1 import func1
from ..module3 import func3


def func4():
    print("This is func4 from module4 in subpackage2 of package2")
    func1()
    func3()


print("module4's __package__ is %s " % __package__)


"""
main.py 输出
module2's __package__ is package1.subpackage1 
module4's __package__ is package2.subpackage2 
This is func2 from module2 in subpackage1 of package1
This is func1 from module1 in package1
This is func4 from module4 in subpackage2 of package2
This is func1 from module1 in package1
This is func3 from module3 in package2

"""

# 可以看出 module2 的__package__中 . 对应subpackage1, ..对应package1。 所以在module2 中 from ..module1 import func1
# 会从package1包中查找module1 然后导入其中的func1.

# module4 的导入也是类似

相对导入个人感悟先写到这。更深入的了解可以看看这两篇文章

  1. 包导入机制
  2. 导入问题原因探究

标签:__,python,py,module1,导入,思考,package1,import
From: https://blog.csdn.net/Agion_n/article/details/145261833

相关文章

  • Python进阶:深入理解import机制与importlib的妙用
    目录一、Pythonimport机制概述1.1import语句的基本用法1.2模块缓存机制1.3导入搜索路径1.4导入钩子和查找器二、importlib的妙用2.1动态模块导入2.2使用importlib实现插件系统2.3重新加载模块三、总结在Python编程的世界里,import语句是开发者最常用的工......
  • Python识别处理验证码技术详解
    目录一、验证码的种类二、OCR技术简介三、使用OCR技术识别验证码1.安装所需库2.下载和处理验证码图片3.使用OCR进行识别4.完整代码示例四、处理复杂验证码五、案例:识别古诗文网验证码六、总结验证码作为一种常见的安全手段,广泛应用于各种网站和应用中,以防止......
  • MySQL里面的时间与UNIX时间戳,解决2038年问题的思考
    当前时间:NOW()当前时间:NOW()函数,传入参数是一个整数类型,传入参数可以是:空(0)、1~6;代表时间精度(秒后面的精度)。SELECTNOW(),NOW(0),NOW(1),NOW(2),NOW(3),NOW(4),NOW(5),NOW(6);如下:NOW()NOW(0)NOW(1)NOW(2)2025-01-2009:47:012025-01-2009:47:012025-01-......
  • Python 列表推导和生成器表达式的区别点
    列表推导(ListComprehensions)和生成器表达式(GeneratorExpressions)在Python中有着相似的语法,但它们的行为和用途有所不同。以下是两者之间的主要区别:1.内存使用列表推导:创建一个完整的列表,所有元素都会被立即计算并存储在内存中。squares_list=[x**2forxinrange(1......
  • Python 实战-优化排班表节省成本
    1.基础概念:理解排班表排班表,顾名思义,就是安排员工工作时间的表格。在餐馆中,它通常需要考虑员工的可用性、工作时间限制、用餐高峰时段等因素。2.使用列表存储员工信息首先,我们需要一个数据结构来存储员工信息。Python中的列表是一个不错的选择。#员工信息列表,包括姓名、......
  • [oeasy]python062_提示符是怎么来的_[词根溯源]prompt_input_输入函数_提示符
    提示符是怎么来的_[词根溯源]prompt_input_输入函数_提示符回忆上次内容上次讲的是从键盘输入变量的值 input函数可以接收到输入字符串存在变量里   添加图片注释,不超过140字(可选) input函数的参数叫prompt......
  • 【python 基础】Python 格式化输出 & 加号的使用
    1.百分号操作符(%)百分号操作符用于格式化输出,允许在字符串中插入占位符。常用格式说明:%s:字符串类型%d:整数类型%f:浮点数类型示例代码:name="Tom"age=20score=90.5gender="Male"print("Name:%s,Age:%d,Gender:%s,Score:%.2f"%(name,age,gender,......
  • ElasticSearch Python 使用
    目录依赖下载连接elasticsearch配置忽略响应状态码示例ElasticsearchforPython之操作结果过滤ElasticSearch(es对象)Indices(es.indices)Cluster(集群相关)Node(节点相关)Cat(一种查询方式)Snapshot(快照相关)Task(任务相关)依赖下载pipinstallelasticsearch#豆瓣源pipinstall-ihtt......
  • 为什么刷题想得越多,考得反而越差?---过拟合现象带来的思考和启迪
    文章目录1.声明2.开篇3.问题的引入4.总结5.正则化的思想解释6.奥卡姆剃刀原理7.对于刷题现象的解释8对于现实生活的指导意义9.思考和启迪1.声明这个系列的文章用来记录学习这个漫士沉思录(b站知名up主)的相关的科普视频,后续可能会有这个领域的其他的博主,例如乐天垂星之......
  • 用Python实现SVM搭建金融反诈模型(含调试运行)
    1.概述信用卡盗刷一般发生在持卡人信息被不法分子窃取后,复制卡片进行消费或信用卡被他人冒领后激活并消费等情况下。一旦发生信用卡盗刷,持卡人和银行都会遭受一定的经济损失。本节要运用支持向量机分类算法搭建一个金融反欺诈模型。2.数据集使用的数据集共有1000条客户信用......