Python modules与packages

Python的Modules是可执行的文件,用于组织代码,可通过import导入。__name__变量标识模块是否为主模块。搜索模块路径sys.path包括当前目录、PYTHONPATH和默认安装路径。编译后的模块存储在__pycache__中。Packages是模块的命名空间组织方式,通过__init__.py定义层级,import *应谨慎使用,可定义__all__控制导入。内部包引用支持绝对和相对路径。

Modules

在Python的解释器中实时输入和输出,当你退出解释器时,你定义的函数和变量就会丢失。所以,如果你想写一个长点的应用程序,最好用编辑器去写你想输入到解释器的东西。这就是大家说的写一个脚本。当程序变的很长了,为了维护方便,你就会想把它拆解到几个文件里。你或许还想定义一个简单的可复用的函数,防止在其它多个程序里重复拷贝。

Python支持你将这些定义放入一个文件,然后在一个脚本或者在解释器的交互实例中使用他们,这样的一个文件就是一个module。module中的定义可以被导入到其它的module中或者主module中。

一个module是一个文件包含Python定义和表述。文件的命名就是模块名.py。在一个module中,模块的名字可以通过一个全局变量__name__来获得。

例如,用编辑器创建一个文件fibo.by,内容如下:

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

则输出为:

 

 

 

 

 

 

 

更多关于Module的介绍

一个module不仅可以包含函数定义还可以包含可执行的表述。这些表述可以用来初始化module。它们近在第一次import的时候或者这个脚本被执行时执行。

模块还可以导入其它模块,当你的模块有更新的时候,你需要重新导入或者load这个module。

像脚本一样执行module __main__

当我们如下执行没有事情发生,不像我们import它之后可直接调用。如果我们想像import以下而执行该脚本,则

python fibo.py

如果我们想像import了该module而执行该脚本,则需要更改代码如下:

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

if __name__ == "__main__":
    import sys
    fib(int(sys.argv[1]))

则执行结果为:

当我们在命令行运行该脚本时,该模块作为主模块执行,而当被import时,该模块不是主模块,则不会被执行。

我们这样做的好处是提供一个方便的用户的模块接口,或者为了执行测试。

模块的搜索路径 sys.path

当你试图导入一个叫spam的模块,解释器会首先搜索内部模块,如果内部模块中没有这样的模块名,则在sys.path的一系列目录中查找是否有命名为spam.py的文件。sys.path通常初始化为:

  • 当前目录
  • PYTHONPATH
  • 默认安装依赖的路径

找到后更改下sys.path, 把它放去当前目录的路径中。

编译后的Python文件

为了加速去加载模块,Python高速缓存每一个编译的module放到__pycache__目录下,命名为moudle-python version.pyc。Python检测源码的编辑日期来判断是否需要重新编译。这是一个自动过程。编译后的模块与平台无关,在不同的系统之间可以共享。

Python在以下两种情况不会去检测高速缓存:

  • 总是编译但是并不存储
  • 没有源码的模块(在非源码分发中,编译好的模块必须位于源码目录)

一些更高深一些的建议:

  • 可使用-0/-00开关去减少编译模块的大小。-0移除了断言,-00移除了断言和文档说明。有一些程序需要断言和文档说明,有些并不需要,请根据需要控制开关。优化后的模块通常有‘opt’标签并会小一些。
  • 高速缓存并不会使该模块执行的速度加快,而只会加快其被加载时的时间。
  • compileall模块会编译目录中所有的模块
  • 针对这一过程,更详细的流程介绍,可参见 PEP 3147.

 

Packages

Packages是一种组织Python模块命名空间的方法。例如,一个模块为A.B指明子模块B在包A中。

假定我们要开发一个处理声音文件和数据的包。需要支持:

  • 处理不同的文件格式
  • 支持不同的声音效果
  • 支持其它定制和花样选择

则我们可以定义的目录结果为:

(.jira_helper) [wlin@MiWiFi-R4A-srv sound]$ tree
.
|-- effects
|   |-- echo.py
|   |-- __init__.py
|   `-- surround.py
|-- filters
|   |-- __init__.py
|   `-- vocoder.py
|-- formats
|   |-- __init__.py
|   `-- wavread.py
`-- __init__.py

3 directories, 8 files

当importing包时,Python会按照sys.path去找package。当目录下含有"__init__.py"文件时,Python将其看为包,这样__init__.py的层级结构就表明了包的层级结构,如上目录结构,我们可以如下调用:

In [1]: import sound.
sound.effects  sound.filters  sound.formats  


In [1]: import sound.effects
sound.effects

In [1]: import sound.effects.
sound.effects.echo      sound.effects.surround  

In [1]: import sound.effects.echo

In [1]: from sound.effects.echo import ECHO

In [2]: ECHO
Out[2]: 'Aha..'

In [3]: from sound.effects.echo import echo

In [4]: echo()
Echo Function

如上,当使用 import item时,只能import到module或者package, 无法import到变量和函数。而使用from module/package后则可以引用到变量和函数。

 

关于importing * 

我们希望通过importing *引入所有包中的子模块,但实际上,除了使加载时间变长,且会让情况变的很难控制,它会加载这个模块中所有的定义在该模块中的名字。

所以,我们尽量不单独使用import *, 而使用准确引入。而子模块很多,确实想使用import *, 则需要在__init__.py定义__all__=['module1','module2'...]即可。

内部包引用

如sound包,sound.filters.vecoder需要用echo.effects中的模块,则可以使用绝对路径引用‘from sound.effects import echo’,也可以使用相对路径 ‘from . import echo’或者 'from .. import formats'

则定义为:

from . import surround
from ..filters import vocoder

def echo():
    print("Echo Function")
    surround.echo()
    vocoder.echo()

ECHO = "Aha.."

输出为:


In [2]: from sound.effects import echo

In [3]: echo.echo()
Echo Function
Hello surround function
Hello vecoder function

 

切记,相对路径时相对于当前模块。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值