page contents

python模块详解

模块(module)其实就是py文件,里面定义了一些函数、类、变量等 包(package)是多个模块的聚合体形成的文件夹,里面可以是多个py文件,也可以嵌套文件夹 库是参考其他编程语言的说法,是指完成一定功能的代码集合,在python中的形式就是模块和包
  • 模块的简单调用

比如我们有一个trymodule的文件夹,里面有一个first.py文件,文件中的内容如下

a = 1
def myfun(s):
print(s + 1)
复制代码

在trymodule的文件夹下打开命令行窗口(按住shift单击鼠标右键,选择“在此处打开命令窗口”),输入python进入命令行交互模式

>>> import first
>>> a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> first.a
1
>>> first.myfun(2)
3
复制代码

所以说first.py文件就是一个模块,可以用import导入,里面变量都要用first.前缀来引用,如果想不使用这个前缀可以这样

>>> from first import a
>>> a
1
复制代码

其他用法如下

# 重命名
>>> from first import myfun as addone
>>> addone(4)
5
# 导入模块中全部变量
>>> from first import *
>>> myfun(2)
3
# 一次导入多个变量
>>> from first import a, myfun
>>> a
1
复制代码

包的导入

在trymodule文件夹中新建folder1文件夹,我们想让folder1文件夹成为一个包。文件夹里新建abcd.py文件,文件中内容如下

b = 2
class Myclass:
def __init__(self, name, age):
self.name = name
self.age = age
def get_info(self):
print('my name is {name} and age is {age}'.format(name = self.name, age = self.age))
复制代码

此时在folder1文件夹中新建一个__init__.py文件,否则程序会将这个文件夹当成普通文件夹来处理而不是一个包。这个__init__.py文件中可以什么都不填。

此时文件结构如下

trymodule
first.py
├───folder1
│ │ abcd.py
│ │ __init__.py
复制代码

我们还是在trymodule文件夹下打开命令行,进入python交互模式

我们来看一下下面几种导入方式

>>> import folder1
>>> folder1.abcd.b
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'folder1' has no attribute 'abcd'
>>> from folder1 import abcd
>>> bob = abcd.Myclass(name = 'Bob', age = 20)
>>> bob.name
'Bob'
>>> bob.get_info()
my name is Bob and age is 20
>>> from folder1.abcd import b
>>> b
2
>>> import folder1.abcd
>>> abcd.b
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'abcd' is not defined
>>> folder1.abcd.b
2
>>> import folder1.abcd as aa
>>> aa.b
2
复制代码

注意:

  • 只是导入包不能随便使用其中的模块,要导入到具体模块或者变量的层次
  • 文件夹与文件之间可以用.也可以用from import格式,而文件与里面的变量之间只能用from import格式,即不能import folder1.abcd.b

特殊的__init__.py文件

__init__.py文件其实是一个特殊的文件,它相当于名为folder1模块,即如果使用import folder1则可以调用在__init__.py文件文件中定义的变量。

将__init__.py文件编写如下

from folder1.abcd import b
c = 3
复制代码

在trymodule文件夹下打开命令行,进入python交互模式

>>> import folder1
>>> folder1.c
3
>>> folder1.b
2
>>> from folder1 import b
>>> b
2
复制代码

对比之前的from folder1.abcd import b,使用__init__.py文件可以将常用的一些变量导入以方便调用。

另外需要注意两点

  • __init__.py文件编写时,如果要导入其他模块中的变量,即使__init__.py文件和abcd.py文件在同一个文件夹下,也不能from abcd import b,要从abcd文件从哪里来的开始写,即从包的名称开始。
  • folder1文件夹里的嵌套文件夹内不需要新建__init__.py文件即可像模块一样调用,但是一般还是要新建这个文件,可以方便地导入常用变量。

导入模块的搜索路径

用import hello时,python会搜寻hello.py文件,搜索顺序如下

  • 首先搜寻内置模块是否有hello(所以我们定义的模块名不要和内置模块相同)
  • 如果内置模块没有,则看下面这些目录里有没有
>>> import sys
>>> sys.path
['', 'C:\\Program Files\\Anaconda3\\python35.zip', 'C:\\Program Files\\Anaconda3\\DLLs', 'C:\\Program Files\\Anaconda3\\lib', 'C:\\Program Files\\Anaconda3', 'C:\\Program Files\\Anaconda3\\lib\\site-packages', 'C:\\Program Files\\Anaconda3\\lib\\site-packages\\Sphinx-1.4.6-py3.5.egg', 'C:\\Program Files\\Anaconda3\\lib\\site-packages\\snownlp-0.12.3-py3.5.egg', 'C:\\Program Files\\Anaconda3\\lib\\site-packages\\win32', 'C:\\Program Files\\Anaconda3\\lib\\site-packages\\win32\\lib', 'C:\\Program Files\\Anaconda3\\lib\\site-packages\\Pythonwin', 'C:\\Program Files\\Anaconda3\\lib\\site-packages\\setuptools-27.2.0-py3.5.egg']
复制代码

其中第一个''表示当前的工作路径,我们可以看出安装的第三方包所在路径('C:\\Program Files\\Anaconda3\\lib\\site-packages')也在这个列表之中,所以无论工作路径在哪里,都能搜寻到这些包。

如果想添加搜索路径,可以参考这篇文章

__all__

首先要明确,import *的方式无法导入以下划线开头的变量名

__init__.py文件内容更改如下

from folder1.abcd import b
c = 3
_e = 4
复制代码

python交互模式下

>>> from folder1 import *
>>> c
3
>>> _e
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '_e' is not defined
复制代码

而如果指定导入是可以的

>>> from folder1 import c
>>> c
3
>>> from folder1 import _e
>>> _e
4
复制代码

如果定义了__all__,则import *就可以导入下划线开头的变量

__init__.py文件内容更改如下

from folder1.abcd import b
__all__ = ['c', '_e']
c = b + 1
_e = 4
复制代码

python交互模式下

>>> from folder1 import *
>>> b
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'b' is not defined
>>> c
3
>>> _e
4
复制代码

可见import *只会导入__all__中指定的变量,无论是否以下划线开头。这样限制可以防止import *命令导入太多变量污染命名空间,过滤掉一些中间变量如b

绝对引用与相对引用

python中的import分为绝对引用和相对引用两种。它们之间的差异在于,引用模块时 定位被引用模块位置 的方式不同

  • 绝对引用是明确指定最高级文件(夹),文件之间用.连接,依次下来达到待引用模块。我们上面的所有用法都属于绝对引用。
  • 而相对引用是 指定待引用模块与当前文件的相对位置,.表示上一级文件

在这样的文件结构下

trymodule
first.py
├───folder1
│ │ abcd.py
│ │ __init__.py
复制代码

编写__init__.py文件,其中要引用abcd.py文件中的变量

  • 绝对引用是from folder1.abcd import b
  • 相对引用是from .abcd import b

相对引用中,.是指父文件(也有from . import xxx的用法),.xxx是指同一层文件,..xxx则是与父文件夹同级的xxx文件(多一个.表示多往上一层)

一般用哪个呢?

python3之后官方推荐用绝对引用的方式,只有当模块中文件关系非常复杂时相对引用才会有优势。

import运行本质

使用import语句,要明确两件事

(1)执行导入模块命令时,会首先检查待导入的模块是否在当前已有模块之中,如果有则跳过import。因此模块之间相互引用不会导致无限循环。

查看当前已导入模块使用下面方法

import sys
sys.modules
复制代码

得到结果是一个字典,键是模块名,值是文件所在路径

(2)import语句与文件执行

在这样的文件结构下

trymodule
first.py
├───folder1
│ │ abcd.py
│ │ __init__.py
复制代码

folder1是一个package,abcd是一个module

  • import folder1 只是导入package,相当于执行__init__.py文件
  • from folder import abcd则执行了__init__.py文件文件与abcd.py文件
  • from folder1.abcd import b其实也执行了__init__.py文件文件与abcd.py文件

(要知道执行了什么,可以在这些文件之中添加print语句,看是否打印出结果)

知道这个执行原理,可以更好理解前面得到的一些结论

  • 首先是在__init__.py文件中什么都没有的情况下,import folder1无法调用abcd模块中的变量,是因为相当与运行了一个空文件,没有将整个包导入工作空间
  • abcd模块中定义了print语句后,import两次,只有第一次会print出值,说明第二次检查出模块已在导入之列,忽略了这条import命令

更多运行细节可以参考这篇文章

if __name__ == '__main__'

我们经常会在别人的代码中发现if __name__ == '__main__',为了理解它的作用,我们来看下面的例子

在folder1文件夹下新建new.py文件,里面内容为

print(__name__)
复制代码

在folder1文件夹下打开命令行,输入

python new.py
复制代码

返回结果是__main__

在trymodule文件夹下打开命令行,进入python交互模式

>>> from folder1 import new
folder1.new
>>> print(__name__)
__main__
>>> print(new.__name__)
folder1.new
复制代码

上面测试结果说明直接运行文件和import文件是有差异的,差异在于二者的__name__变量不同。__name__变量是一个特殊的变量,每个py文件运行时都会对应一个__name__变量,即使在交互模式下也可以查看这个变量值。

所以if __name__ == '__main__'的作用就很好理解了,即import时不执行下面的代码,只有在直接执行这个文件时才运行之后的代码。这算是一种约定俗成的写法,如果不怕文件被import,可以不用这个。

  • 发表于 2020-12-22 12:04
  • 阅读 ( 630 )
  • 分类:Python开发

0 条评论

请先 登录 后评论
Pack
Pack

1135 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 1474 文章
  3. Pack 1135 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章