当前位置: 首页 > news >正文

Python:import语句的使用(详细解析)(一)

相关阅读

Pythonicon-default.png?t=O83Ahttps://blog.csdn.net/weixin_45791458/category_12403403.html?spm=1001.2014.3001.5482


        import语句是Python中一个很重要的机制,允许在一个文件中访问另一个文件的函数、类、变量等,本文就将进行详细介绍。

        在具体谈论import语句前,首先介绍相关的前置知识——导入的搜索目录。

导入的搜索目录

        既然要求在一个文件访问其他文件,那么如何找到其他文件就是一个问题,这由sys包中的path列表决定,它在Python解释器在启动时会自动初始化,并属于整个Python解释器而不是某个文件。

        初始化后的sys.path列表由多个元素组成,每个元素都是一个字符串,表示在导入时会依次搜索的路径(除内建模块外,比如math)。

        sys.path列表第一个元素会根据Python解释器的启动方式而定:

        1、如果是以交互式启动,则会被设置为空字符串,以表示当前工作目录,如例1所示(空字符串永远代表当前工作目录,即使在交互式Python中使用os.chdir函数改变了当前工作目录)。

# 例1
# 命令行
(test) C:\Users\12078\Desktop>python
Python 3.10.14 | packaged by Anaconda, Inc. | (main, May  6 2024, 19:44:50) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', 'D:\\Anaconda\\envs\\test\\python310.zip', 'D:\\Anaconda\\envs\\test\\DLLs', 'D:\\Anaconda\\envs\\test\\lib', 'D:\\Anaconda\\envs\\test', 'D:\\Anaconda\\envs\\test\\lib\\site-packages']

        2、如果以python  -m命令启动,则会被设置当前工作目录,如例2所示(注意其与例1的区别)。

# 例2
# 文件test1.py
import sys
print(sys.path)# 命令行
(test) C:\Users\12078\Desktop>python -m example.test1
['C:\\Users\\12078\\Desktop', 'D:\\Anaconda\\envs\\test\\python310.zip', 'D:\\Anaconda\\envs\\test\\DLLs', 'D:\\Anaconda\\envs\\test\\lib', 'D:\\Anaconda\\envs\\test', 'D:\\Anaconda\\envs\\test\\lib\\site-packages']

        3、如果是以普通的python命令启动(最常见),则会被设置为命令行中脚本文件所在的目录,如例3所示(本文将这种情况为例)。

# 例3
# 文件test1.py
import sys
print(sys.path)# 命令行
(test) C:\Users\12078\Desktop>python .\example\test1.py
['C:\\Users\\12078\\Desktop\\example', 'D:\\Anaconda\\envs\\test\\python310.zip', 'D:\\Anaconda\\envs\\test\\DLLs', 'D:\\Anaconda\\envs\\test\\lib', 'D:\\Anaconda\\envs\\test', 'D:\\Anaconda\\envs\\test\\lib\\site-packages']

        sys.path列表中的其他元素还包括环境变量PYTHONPATH中指定的目录、标准库路径、site-packages目录等。该列表可以在程序执行时被添加、删除元素,就像一个普通的列表那样,但是这是需要谨慎,因为可能出现导入相关的问题。

import语句的语法

        下面是Python官方文档中,对于import语句的描述,由于imort语句分为基本import语句和from import语句,下面将分别讨论。

import_stmt     ::=  "import" module ["as" identifier] ("," module ["as" identifier])*| "from" relative_module "import" identifier ["as" identifier]("," identifier ["as" identifier])*| "from" relative_module "import" "(" identifier ["as" identifier]("," identifier ["as" identifier])* [","] ")"| "from" relative_module "import" "*"
module          ::=  (identifier ".")* identifier
relative_module ::=  "."* module | "."+

基本import语句

        基本import语句的执行分两步进行,首先会在导入的搜索目录中,根据模块的import路径查找并导入(如果已导入,则不会重复导入),随后在import语句执行位置所在的命名空间定义若干标识符。

import路径

        一个以.py后缀的文件或包(即目录)可以代表一个模块,对于import路径,路径分隔符不再是斜杠(对于Linux系统)或反斜杠(对于Windows系统)而是点,且对于.py后缀的文件不添加.py后缀。

        图1展示了例3的文件结构,例4给出了几个import路径的示例,假设执行的是test1.py文件(因此'C:\\Users\\12078\\Desktop\\example'是sys.path列表的第一个元素)。

图1 文件结构 

# 例4
Package                        # 这是一个包的import路径
Package.__init__               # 这是一个包的import路径, 与上等价
Package.test2                  # 这是一个.py文件的import路径
example.Package                # 这是不合法的, 要相对sys.path中的路径
example.Package.test2          # 这是不合法的, 要相对sys.path中的路径
Package.test2.func1            # 这是不合法的, 一个函数不是模块
模块导入

        导入一个模块,会执行模块内的所有代码(包也是模块,对于它是指执行了包中的__init__.py文件),并在sys.modules字典(它和sys.path一样属于整个Python解释器)中记录模块的import路径和模块的绝对路径(Python解释器根据import路径防止重复导入),如例5所示,假设执行的是test1.py文件。

# 例5
# 文件test1.py
import sys
print(sys.modules)
import Package.test2
print(sys.modules)
import Package# 文件__init__.py
def fun():print("func in __init__.py")
print("This is a package's __init__.py")# 文件test2.py
def fun1c():print("func1 in test2.py")
def fun2c():print("func2 in test2.py")print("This is test2.py")# 命令行
(test) C:\Users\12078\Desktop>python .\example\test1.py
{'sys': <module 'sys' (built-in)>, 'builtins': <module 'builtins' (built-in)>, '_frozen_importlib': <module '_frozen_importlib' (frozen)>, '_imp': <module '_imp' (built-in)>, '_thread': <module '_thread' (built-in)>, '_warnings': <module '_warnings' (built-in)>, '_weakref': <module '_weakref' (built-in)>, '_io': <module '_io' (built-in)>, 'marshal': <module 'marshal' (built-in)>, 'nt': <module 'nt' (built-in)>, 'winreg': <module 'winreg' (built-in)>, '_frozen_importlib_external': <module '_frozen_importlib_external' (frozen)>, 'time': <module 'time' (built-in)>, 'zipimport': <module 'zipimport' (frozen)>, '_codecs': <module '_codecs' (built-in)>, 'codecs': <module 'codecs' from 'D:\\Anaconda\\envs\\test\\lib\\codecs.py'>, 'encodings.aliases': <module 'encodings.aliases' from 'D:\\Anaconda\\envs\\test\\lib\\encodings\\aliases.py'>, 'encodings': <module 'encodings' from 'D:\\Anaconda\\envs\\test\\lib\\encodings\\__init__.py'>, 'encodings.utf_8': <module 'encodings.utf_8' from 'D:\\Anaconda\\envs\\test\\lib\\encodings\\utf_8.py'>, '_codecs_cn': <module '_codecs_cn' (built-in)>, '_multibytecodec': <module '_multibytecodec' (built-in)>, 'encodings.gbk': <module 'encodings.gbk' from 'D:\\Anaconda\\envs\\test\\lib\\encodings\\gbk.py'>, '_signal': <module '_signal' (built-in)>, '_abc': <module '_abc' (built-in)>, 'abc': <module 'abc' from 'D:\\Anaconda\\envs\\test\\lib\\abc.py'>, 'io': <module 'io' from 'D:\\Anaconda\\envs\\test\\lib\\io.py'>, '__main__': <module '__main__' from 'C:\\Users\\12078\\Desktop\\example\\test1.py'>, '_stat': <module '_stat' (built-in)>, 'stat': <module 'stat' from 'D:\\Anaconda\\envs\\test\\lib\\stat.py'>, '_collections_abc': <module '_collections_abc' from 'D:\\Anaconda\\envs\\test\\lib\\_collections_abc.py'>, 'genericpath': <module 'genericpath' from 'D:\\Anaconda\\envs\\test\\lib\\genericpath.py'>, '_winapi': <module '_winapi' (built-in)>, 'ntpath': <module 'ntpath' from 'D:\\Anaconda\\envs\\test\\lib\\ntpath.py'>, 'os.path': <module 'ntpath' from 'D:\\Anaconda\\envs\\test\\lib\\ntpath.py'>, 'os': <module 'os' from 'D:\\Anaconda\\envs\\test\\lib\\os.py'>, '_sitebuiltins': <module '_sitebuiltins' from 'D:\\Anaconda\\envs\\test\\lib\\_sitebuiltins.py'>, '_distutils_hack': <module '_distutils_hack' from 'D:\\Anaconda\\envs\\test\\lib\\site-packages\\_distutils_hack\\__init__.py'>, 'site': <module 'site' from 'D:\\Anaconda\\envs\\test\\lib\\site.py'>}
This is a package's __init__.py
This is test2.py
{'sys': <module 'sys' (built-in)>, 'builtins': <module 'builtins' (built-in)>, '_frozen_importlib': <module '_frozen_importlib' (frozen)>, '_imp': <module '_imp' (built-in)>, '_thread': <module '_thread' (built-in)>, '_warnings': <module '_warnings' (built-in)>, '_weakref': <module '_weakref' (built-in)>, '_io': <module '_io' (built-in)>, 'marshal': <module 'marshal' (built-in)>, 'nt': <module 'nt' (built-in)>, 'winreg': <module 'winreg' (built-in)>, '_frozen_importlib_external': <module '_frozen_importlib_external' (frozen)>, 'time': <module 'time' (built-in)>, 'zipimport': <module 'zipimport' (frozen)>, '_codecs': <module '_codecs' (built-in)>, 'codecs': <module 'codecs' from 'D:\\Anaconda\\envs\\test\\lib\\codecs.py'>, 'encodings.aliases': <module 'encodings.aliases' from 'D:\\Anaconda\\envs\\test\\lib\\encodings\\aliases.py'>, 'encodings': <module 'encodings' from 'D:\\Anaconda\\envs\\test\\lib\\encodings\\__init__.py'>, 'encodings.utf_8': <module 'encodings.utf_8' from 'D:\\Anaconda\\envs\\test\\lib\\encodings\\utf_8.py'>, '_codecs_cn': <module '_codecs_cn' (built-in)>, '_multibytecodec': <module '_multibytecodec' (built-in)>, 'encodings.gbk': <module 'encodings.gbk' from 'D:\\Anaconda\\envs\\test\\lib\\encodings\\gbk.py'>, '_signal': <module '_signal' (built-in)>, '_abc': <module '_abc' (built-in)>, 'abc': <module 'abc' from 'D:\\Anaconda\\envs\\test\\lib\\abc.py'>, 'io': <module 'io' from 'D:\\Anaconda\\envs\\test\\lib\\io.py'>, '__main__': <module '__main__' from 'C:\\Users\\12078\\Desktop\\example\\test1.py'>, '_stat': <module '_stat' (built-in)>, 'stat': <module 'stat' from 'D:\\Anaconda\\envs\\test\\lib\\stat.py'>, '_collections_abc': <module '_collections_abc' from 'D:\\Anaconda\\envs\\test\\lib\\_collections_abc.py'>, 'genericpath': <module 'genericpath' from 'D:\\Anaconda\\envs\\test\\lib\\genericpath.py'>, '_winapi': <module '_winapi' (built-in)>, 'ntpath': <module 'ntpath' from 'D:\\Anaconda\\envs\\test\\lib\\ntpath.py'>, 'os.path': <module 'ntpath' from 'D:\\Anaconda\\envs\\test\\lib\\ntpath.py'>, 'os': <module 'os' from 'D:\\Anaconda\\envs\\test\\lib\\os.py'>, '_sitebuiltins': <module '_sitebuiltins' from 'D:\\Anaconda\\envs\\test\\lib\\_sitebuiltins.py'>, '_distutils_hack': <module '_distutils_hack' from 'D:\\Anaconda\\envs\\test\\lib\\site-packages\\_distutils_hack\\__init__.py'>, 'site': <module 'site' from 'D:\\Anaconda\\envs\\test\\lib\\site.py'>, 'Package': <module 'Package' from 'C:\\Users\\12078\\Desktop\\example\\Package\\__init__.py'>, 'Package.test2': <module 'Package.test2' from 'C:\\Users\\12078\\Desktop\\example\\Package\\test2.py'>}

        可以看出,在test2.py文件(导入)执行前,Package包中的__init__.py文件先(导入)执行了,因为所有import路径上的目录(包)会从浅到深依次导入,最后导入目标模块,从导入后的sys.modules字典中也可以看到Package包比Package.test2模块添加得更早。如果在此之后,再次导入Package,__init__.py文件不会再(导入)执行了,因为Python解释器会避免重复导入。

定义标识符

        在import语句执行后,会在当前命名空间定义标识符,用于访问导入的模块中全局命名空间下的函数、类、变量等,需要注意的是导入是针对整个Python解释器而言的,而定义标识符是针对在当前命名空间而言的,两个步骤并不一定会全部完成(如例8所示)。

        例6中展示了在当前命名空间定义标识符的过程。

# 例6
# 文件test1.pyimport Package.test2 # 首先导入(执行)Package包,随后导入(执行)Package.test2模块, 最后在全局命名空间定义标识符Package和Package.test2
Package.func()         # 可以调用__init__.py中的函数了
Package.test2.func1()  # 可以调用test2.py中的函数了def ttt():Package.func() # 局部命名空间可以访问全局命名空间的标识符ttt() # 调用ttt函数# 文件__init__.py
def func():print("func in __init__.py")
print("This is a package's __init__.py")# 文件test2.py
def func1():print("func1 in test2.py")
def func2():print("func2 in test2.py")print("This is test2.py")# 命令行
(test) C:\Users\12078\Desktop>python .\example\test1.py
This is a package's __init__.py
This is test2.py
func in __init__.py
fun1c in test2.py
func in __init__.py

控制导入模块的执行

        如果希望某些代码在模块导入时不执行,则可以如例7所示,这利用了只有直接执行而非导入执行时,__name__变量才为"__main__"的性质。

# 例7
# 文件test1.pyimport Package.test2 # 首先导入(执行)Package包,随后导入(执行)Package.test2模块, 最后在全局命名空间定义标识符Package和Package.test2
Package.func()         # 可以调用__init__.py中的函数了
Package.test2.func1()  # 可以调用test2.py中的函数了def ttt():Package.func() # 局部命名空间可以访问全局命名空间的标识符ttt() # 调用ttt函数# 文件__init__.py
def func():print("func in __init__.py")if __name__ == "__main__":print("This is a package's __init__.py")# 文件test2.py
def func1():print("func1 in test2.py")
def func2():print("func2 in test2.py")if __name__ == "__main__":print("This is test2.py")# 命令行
(test) C:\Users\12078\Desktop>python .\example\test1.py
func in __init__.py
fun1c in test2.py
func in __init__.py

as子句

        如果模块的路径很长,则定义的标识符也会很长,此时使用as子句就可以用指定的标识符代表该模块,如例8所示,需要小心这可能会导致标识符的覆盖问题。

# 例8
# 文件test1.py
import Package.test2 as t2 # 首先导入(执行)Package包,随后导入(执行)Package.test2模块, 最后在全局命名空间定义标识符t2
# Package.func()   不可以调用__init__.py中的函数,因为虽然Package包被导入,但此时没有定义任何标识符
# Package.test2.func1() 不可以调用test2.py中的函数,因为虽然Package.test2模块被导入,但此时没有定义该标识符
t2.func1()  # 需要用新的标识符调用test2.py中的函数import Package.test2 # 由于Package包和Package.test2模块已被导入,直接在全局命名空间定义标识符Package和Package.test2
Package.func()
Package.test2.func1()# 文件__init__.py
def func():print("func in __init__.py")if __name__ == "__main__":print("This is a package's __init__.py")# 文件test2.py
def func1():print("func1 in test2.py")
def func2():print("func2 in test2.py")if __name__ == "__main__":print("This is test2.py")# 命令行
(test) C:\Users\12078\Desktop>python .\example\test1.py
func in __init__.py
fun1c in test2.py
func in __init__.py
多重import语句 

        多个import语句可以合并为同一个语句,当语句包含多个子句(由逗号分隔)时这两个步骤将对每个子句分别执行,如同这些子句被分成独立的import语句一样,例9重写了例8。

# 例9
# 文件test1.py
import Package.test2 as t2, Package.test2 # 首先导入(执行)Package包, 随后导入(执行)Package.test2模块, 接着在全局命名空间定义标识符t2, 最后在全局命名空间定义标识符Package和Package.test2
t2.func1()  # 用新的标识符调用test2.py中的函数
Package.func()
Package.test2.func1()# 文件__init__.py
def func():print("func in __init__.py")if __name__ == "__main__":print("This is a package's __init__.py")# 文件test2.py
def func1():print("func1 in test2.py")
def func2():print("func2 in test2.py")if __name__ == "__main__":print("This is test2.py")# 命令行
(test) C:\Users\12078\Desktop>python .\example\test1.py
fun1c in test2.py
func in __init__.py
fun1c in test2.py

        至此,所有关于基本import语句的内容就结束了,由于篇幅问题,from import语句将在下一篇文章中讨论。 

相关文章:

  • C语言 | Leetcode C语言题解之第448题找到所有数组中消失的数字
  • excel不经过后台实现解析和预览(vue)
  • Docker Compose 搭建 nacos 集群
  • react-问卷星项目(3)
  • 多普勒频移
  • MVC core 、MVC framework addTagHelper、htmlhelper 、Environment
  • 1、深入理解Redis线程模型
  • leetcode-链表篇3
  • 会议平台后端优化方案
  • EasyExcel日常使用总结
  • C++模拟实现vector容器【万字模拟✨】
  • LeetCode 53. 最大子数组和
  • [C++] 小游戏 征伐 SLG DNF 0.0.1 版本 zty出品
  • SpringBoot(Java)实现MQTT连接(本地Mosquitto)通讯调试
  • Leetcode 11.乘最多水的容器(字节,快手面试题)
  • Android Volley源码解析
  • Consul Config 使用Git做版本控制的实现
  • JavaScript 事件——“事件类型”中“HTML5事件”的注意要点
  • nodejs:开发并发布一个nodejs包
  • oldjun 检测网站的经验
  • React-生命周期杂记
  • Vue ES6 Jade Scss Webpack Gulp
  • Wamp集成环境 添加PHP的新版本
  • 将 Measurements 和 Units 应用到物理学
  • 前嗅ForeSpider采集配置界面介绍
  • 少走弯路,给Java 1~5 年程序员的建议
  • 学习HTTP相关知识笔记
  • 一道闭包题引发的思考
  • 移动互联网+智能运营体系搭建=你家有金矿啊!
  • ​埃文科技受邀出席2024 “数据要素×”生态大会​
  • ​比特币大跌的 2 个原因
  • (1)Jupyter Notebook 下载及安装
  • (11)(2.1.2) DShot ESCs(四)
  • (4)(4.6) Triducer
  • (C#)Windows Shell 外壳编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令...
  • (LeetCode) T14. Longest Common Prefix
  • (PADS学习)第二章:原理图绘制 第一部分
  • (pt可视化)利用torch的make_grid进行张量可视化
  • (编程语言界的丐帮 C#).NET MD5 HASH 哈希 加密 与JAVA 互通
  • (接口封装)
  • (离散数学)逻辑连接词
  • (每日一问)操作系统:常见的 Linux 指令详解
  • (提供数据集下载)基于大语言模型LangChain与ChatGLM3-6B本地知识库调优:数据集优化、参数调整、Prompt提示词优化实战
  • (转)nsfocus-绿盟科技笔试题目
  • *算法训练(leetcode)第四十五天 | 101. 孤岛的总面积、102. 沉没孤岛、103. 水流问题、104. 建造最大岛屿
  • .NET C# 使用 iText 生成PDF
  • .net 流——流的类型体系简单介绍
  • .NET6实现破解Modbus poll点表配置文件
  • .NET处理HTTP请求
  • .vollhavhelp-V-XXXXXXXX勒索病毒的最新威胁:如何恢复您的数据?
  • 。Net下Windows服务程序开发疑惑
  • /usr/bin/env: node: No such file or directory
  • @Data注解的作用
  • @ModelAttribute注解使用
  • @RequestParam @RequestBody @PathVariable 等参数绑定注解详解