python笔记-模块和包

一、什么是模块

  如果你从Python解释器退出并再次进入,之前的定义(函数和变量)都会丢失。因此,如果你想编写一个稍长些的程序,最好使用文本编辑器为解释器准备输入并将该文件作为输入运行。这被称作编写 脚本 。随着程序变得越来越长,你或许会想把它拆分成几个文件,以方便维护。你亦或想在不同的程序中使用一个便捷的函数, 而不必把这个函数复制到每一个程序中去。

  为支持这些,Python有一种方法可以把定义放在一个文件里,并在脚本或解释器的交互式实例中使用它们。这样的文件被称作 模块 ;模块中的定义可以 导入 到其它模块或者 主模块(你在顶级和计算器模式下执行的脚本中可以访问的变量集合)

  模块是一个包含Python定义和语句的文件。文件名就是模块名后跟文件后缀 .py 。在一个模块内部,模块名(作为一个字符串)可以通过全局变量 __name__ 的值获得

二、模块编写与使用

使用文本编辑器在当前目录下创建一个名为 fibo.py 的文件, 键入以下代码

def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while a < n:
        print(a, end=' ')
        a, b = b, a+b
    print()

def fib2(n):   # return Fibonacci series up to n
    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)
        a, b = b, a+b
    return result

使用模块中的函数
现在进入Python解释器,并用以下命令导入该模块:

>>> import fibo

在当前的符号表中,这并不会直接进入到定义在 fibo 函数内的名称;它只是进入到模块名 fibo 中。你可以用模块名访问这些函数

>>> fibo.fib(1000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.fib2(100)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>> fibo.__name___
'fibo'

如果你想经常使用某个函数,你可以把它赋值给一个局部变量

>>> fib = fibo.fib
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

三、模块导入方法

  1. import 模块名
  2. from 模块名 import 模块中的属性
>>> from fibo import fib, fib2
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
  1. import 模块名 as 新模块名
>>> import fibo as fib
>>> fib.fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
  1. from 模块名 import 模块中的属性 as 新属性名
>>> from fibo import fib as fibonacci
>>> fibonacci(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

注意:

  1. 出于效率的考虑,每个模块在每个解释器会话中只被导入一次。
  2. 因此,如果你更改了你的模块,则必须重新启动解释器, 或者,如果它只是一个要交互式地测试的模块,请使用 importlib.reload(),例如 import importlib; importlib.reload(modulename)

四、脚本方式执行模块

模块里的代码会被执行,就好像你导入了模块一样,但是 __name__ 被赋值为 "__main__"。 这意味着通过在你的模块末尾添加这些代码

if __name__ == "__main__":
    import sys
    fib(int(sys.argv[1]))
  1. 如果模块是被导入的,这些代码是不运行的

五、模块搜索路径

  1. 当一个名为 spam 的模块被导入的时候,解释器首先寻找具有该名称的内置模块
  2. 如果没有找到,然后解释器从 sys.path 变量给出的目录列表里寻找名为 spam.py 的文件

sys.path包含的路径

  1. 包含输入脚本的目录(或者未指定文件时的当前目录)
  2. PYTHONPATH (一个包含目录名称的列表,它和shell变量 PATH 有一样的语法)
  3. 取决于安装的默认设置

六、编译过的python模块

为了加速模块载入,Python在 __pycache__ 目录里缓存了每个模块的编译后版本,名称为 module.version.pyc ,其中名称中的版本字段对编译文件的格式进行编码; 它一般使用Python版本号。例如,在CPython版本3.3中,spam.py的编译版本将被缓存为 __pycache__/spam.cpython-33.pyc。此命名约定允许来自不同发行版和不同版本的Python的已编译模块共存。

Python根据编译版本检查源的修改日期,以查看它是否已过期并需要重新编译。这是一个完全自动化的过程。此外,编译的模块与平台无关,因此可以在具有不同体系结构的系统之间共享相同的库。

Python在两种情况下不会检查缓存。首先,对于从命令行直接载入的模块,它从来都是重新编译并且不存储编译结果;其次,如果没有源模块,它不会检查缓存。为了支持无源文件(仅编译)发行版本, 编译模块必须是在源目录下,并且绝对不能有源模块。

七、包

包是一种通过用“带点号的模块名”来构造 Python 模块命名空间的方法。 例如,模块名 A.B 表示 A 包中名为 B 的子模块

例如, 处理声音包

sound/                          Top-level package
      __init__.py               Initialize the sound package
      formats/                  Subpackage for file format conversions
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  Subpackage for sound effects
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  Subpackage for filters
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...

当导入这个包时,Python搜索 sys.path 里的目录,查找包的子目录

必须要有 __init__.py 文件才能让 Python 将包含该文件的目录当作包。 这样可以防止具有通常名称例如 string 的目录在无意中隐藏稍后在模块搜索路径上出现的有效模块。 在最简单的情况下,__init__.py 可以只是一个空文件,但它也可以执行包的初始化代码或设置 __all__ 变量

7.1 包的导入

  1. 导入包的单个模块
import sound.effects.echo
  • 这会加载子模块 sound.effects.echo 。但引用它时必须使用它的全名
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)
  1. 导入包的子模块
from sound.effects import echo
  1. 直接导入所需的函数或变量
from sound.effects.echo import echofilter

当使用 from package import item 时,item 可以是包的子模块(或子包),也可以是包中定义的其他名称,如函数,类或变量

  1. form package import *: 会导入包__init__.py中的__all__列表变量包含的所有模块

  2. 相对路径导入

from . import echo
from .. import formats
from ..filters import equalizer
  • 请注意,相对导入是基于当前模块的名称进行导入的。由于主模块的名称总是 "main" ,因此用作Python应用程序主模块的模块必须始终使用绝对导入。
原文地址:https://www.cnblogs.com/duyupeng/p/13168273.html