python进阶(二)导入import 机制 | 导入import 用法 工作原理全解析


参考《Python应该如何导入(import)模块及包》梳理

1. 整体概念基本介绍

虽然简简单单的导入import,其实涉及到很多的知识

我们导入往往是一个包,或者包内的一个模块,或者一个模块内的某些函数变量等

所以我们先对,包,模块,函数、变量做一个简单介绍

他们的包含关系是

包package(往往是一个目录/文件夹)》模块module(往往是一个文件)》变量,函数,类

直观来说,一个包往往包含多个模块文件或者一些子包,每个模块文件包含多个变量和函数方法,类等

下面分别是更详细的介绍

1.1 包package

通常包是一个目录

为了将目录视为包,必须在其内部包含一个名为 __init__.py 的文件。__init__.py 文件可以为空,也可以包含包的初始化代码。

1.2 模块 module

通常模块为一个文件,直接使用import来导入就好了。可以作为module的文件类

一个模块内往往包括多个变量,函数

当然实际上可以导入的四种包括

  • 使用Python写的程序( .py文件)
  • C或C++扩展(已编译为共享库或DLL文件)
  • 包(包含多个模块)
  • 内建模块(使用C编写并已链接到Python解释器内)

2 基本语法

这里涉及到名字空间的概念,具体可以看我前一篇博客Python进阶(一)名字空间 | 超详细名字空间解析 内置 全局 局部 调试查看-CSDN博客
名字空间简单理解就是一个变量和值的映射关系

2.1 import直接使用

import直接导入模块,会创建一个新的导入模块名字空间,当前文件会引用这个导入模块的名字空间

import module_name

2.2 from 及其用法

我们可以使用 from 关键字指定需要引入的具体内容:

使用from语句可以将模块中的对象直接导入到当前的名字空间. from语句不创建一个到模块名字空间的引用,而是把被导入模块的一个或多个对象直接放入当前的名字空间:

from module_name import function_name, class_name

from语句支持逗号分割的对象,也可以使用星号*代表模块中下划线开头的所有对象(注意这里导入是不会导入单下划线开头的变量)

from socket import *   # 载入所有对象到当前名字空间  

如果一个模块如果定义有列表__all__,则from module import * 语句只能导入__all__列表中存在的对象。

# module: foo.py  
__all__ = [ 'bar', 'spam' ]     # 定义使用 `*` 可以导入的对象  

3.1 as的用法

也可以使用 as 关键字给模块或内容起别名:

import module_name as alias

另外, as 也可以和 from 联合使用:

from socket import gethostname as hostname  
h = hostname()

3 工作原理

3.1 搜寻

现在有一个问题,就是导入的时候解释器会去哪里搜寻模块?

当我们使用 import 语句时,Python 解释器会在一系列目录中搜索模块(sys.path列表)这些目录包括当前目录(包含运行脚本的目录)、内置模块目录、环境变量 PYTHONPATH 中指定的目录等。

一个典型的sys.path 列表的值:

Linux:
[’’, ‘/usr/local/lib/python2.0’,
‘/usr/local/lib/python2.0/plat-sunos5’,
‘/usr/local/lib/python2.0/lib-tk’,
‘/usr/local/lib/python2.0/lib-dynload’,
‘/usr/local/lib/python2.0/site-packages’]

Windows:
[’’, ‘C:\WINDOWS\system32\python24.zip’, ‘C:\Documents and Settings\weizhong’, ‘C:\Python24\DLLs’, ‘C:\Python24\lib’, ‘C:\Python24\lib\plat-win’, ‘C:\Python24\lib\lib-tk’, ‘C:\Python24\Lib\site-packages\pythonwin’, ‘C:\Python24’, ‘C:\Python24\lib\site-packages’, ‘C:\Python24\lib\site-packages\win32’, ‘C:\Python24\lib\site-packages\win32\lib’, ‘C:\Python24\lib\site-packages\wx-2.6-msw-unicode’]

空字符串 代表当前目录. 要加入新的搜索路径,只需要将这个路径加入到这个列表.

3.2 执行

假设某源代码文件初次引入某一个模块

执行的具体步骤如下

  • 1.为源代码文件中定义的对象创建一个模块名字空间,通过这个名字空间可以访问到模块中定义的函数及变量。
  • 2.在新创建的名字空间里完整执行模块文件和源代码文件。
  • 3.创建一个名为源代码文件的对象,该对象引用模块的名字空间,这样就可以通过这个对象访问模块中的函数及变量,如:
import spam           # 导入并运行模块 spam  
print (spam.a)          # 访问模块 spam 的属性  
spam.foo()  
c = spam.bar()

import语句可以在程序的任何位置使用,你可以在程序中多次导入同一个模块,但模块中的代码 仅仅 在该模块被首次导入时执行。后面的import语句只是简单的创建一个到模块名字空间的引用而已。

这里我们注意到上面的第2点,一旦模块被导入,他的代码就会被执行一遍,但有些时候我不想让模块完整被执行,那么该怎么办呢?

3.3 避免导入模块代码执行

当一个模块被导入时,它的代码会被执行一次。如果你希望某些代码仅在模块被直接运行时而不是被导入时执行,可以使用 if __name__ == "__main__": 来进行条件判断。

if __name__ == "__main__":
    # 这里的代码仅在模块被直接运行时执行

如下所示是一个详细的例子

假设我们有一个名为 example_module.py 的模块文件,内容如下:

# example_module.py

def add_numbers(a, b):
    return a + b

# 如果模块被直接运行,则执行以下代码(比如直接运行python example_module.py)
if __name__ == "__main__":
    x = 5
    y = 10
    result = add_numbers(x, y)
    print(f"The sum of {x} and {y} is: {result}")

在这个例子中,example_module.py 定义了一个简单的函数 add_numbers 用于相加两个数字。然后,在模块的末尾,使用 if __name__ == "__main__": 来判断模块是被导入还是被直接运行。如果模块被直接运行(比如直接运行python example_module.py),就会执行一些特定的代码,例如计算两个数字的和并打印结果。

现在,如果我们在另一个脚本another_script.py中导入这个模块,if __name__ == "__main__": 之后的代码就不会被执行。例如:

# another_script.py

import example_module

result = example_module.add_numbers(8, 12)
print(f"The sum of 8 and 12 is: {result}")

会输出

The sum of 8 and 12 is: 20

在这个例子中,虽然我们导入了 example_module,但由于我们没有直接运行 example_module.py,因此 if __name__ == "__main__": 之后的代码不会执行。只有当 example_module.py 被直接运行时,才会执行这部分代码。

  • 29
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值