python12:模块

到目前为止,你已经可以使用python实现你想要的功能。但当你编码一段时间后,随着代码量的增长,你可能想将你的代码分解为多个文件,便于管理;你也可能想使用一些已经写好的函数,而不用将他们拷贝过来。

为了支持这些功能,python提供了方法将函数定义在一个文件中,并能在其它脚本文件中使用他们,这样的文件就叫做模块。在一个模块中的定义能被导入其它模块或者主模块中。

模块基础

一个模块就是一个文件,包含python的定义和陈述,文件名就是模块名加上后缀.py。在模块内,模块名保存在全局变量__name__中,可以被使用。例如,使用文本编辑器创建一个文件fibo.py,并写入以下内容:

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

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

现在进入python解释器,导入刚创建的模块:

>>> import fibo

这样就在解释器中导入了fibo模块,使用模块名你可以使用模块中的函数:

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

如果你想为一个经常使用的函数分配一个本地名称:

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

模块进阶

一个模块能包含执行代码和函数定义。模块的执行代码在模块被作为一个脚本执行或者被导入时执行。

每个模块都有自己的符号表,作为模块内函数的全局符号表。因此,模块的作者可以在模块内用全局变量,不用担心与其他模块的全局变量冲突。而且,你可以使用modname.itemname方法访问另一个模块的全局变量。

模块能导入其它模块,通常将import放在模块开头,但不强制要求。导入的模块名被放置在模块的全局符号表中。

需要注意如果你不是import模块,而是import模块中的函数,则导入函数所在的模块名不会出现在模块的符号表中,例如:

>>> from fibo import fib, fib2
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 

在这种情况下,fibo是没有被定义的。

你也可以导入模块中定义的所有变量:

>>> from fibo import *
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 

这将导入除了以_开头的所有的变量。通常不要使用这个方法,因为你无法判断导入的模块中的变量是否和你定义的变量重名。

导入*是一种很糟糕的方式,通常会引起可读性很差的代码。

执行模块

你可以在命令行中通过下面的方式执行Python模块:

python fibo.py <arguments>

在模块中的代码将被执行,模块的__name__将被设置为"__main__"。

模块在执行和导入时会做同样的操作,这样,模块的执行代码在导入时也会执行,但通过判定模块名为__main__时才执行执行代码,就可以避免导入时执行代码被执行,如下:

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

这样你就可以保证你的执行代码仅在作为__main__执行时才会执行,你可以将模块的测试代码做这样的处理。

模块搜索路径

当一个名为spam的模块被导入时,解释器首先在内嵌模块中搜索,如果未发现,他将从变量sys.path. sys.path指定的文件夹列表中查找spam.py的文件,该变量的值通过下面的方法指定:

1)包含输入脚本的文件夹(如果没有文件被指定,则为当前文件夹);

2)PYTHONPATH(文件夹名列表,类似于环境变量PATH);

3)安装依赖默认。

初始化后,Python程序能修改sys.path,正在运行包含的脚本的文件夹被放置在搜索路径的开始,在标准库路径之前,即:如果文件夹中的脚本和标准库重名,将优先加载文件夹中的脚本。除非这就是你想要的,否则将导致错误。

“编译”Python文件

为了加快模块加载,Python缓存编译后的模块在__pycache__文件夹,并命名为module.version.pyc,version是Python的版本号。例如:CPython版本3.3下spam.py的编译后版本被缓存为__pycache__/spam.cpython-33.pyc。这样的命名允许模块的不同版本和不同编译后版本共存。

Python会检查源代码的修改日期,和编译后版本比较,确定是否需要重新编译。这个过程是完全自动的,而且,编译后的模块是平台无关的,所以同样的库可以在不同的系统间共享。

在两种情况下Python不检查缓存:1)直接从命令行加载,这时Python总是重编译并且不存储结果;2)如果没有源模块,Python将不检查缓存。为了支持无源代码的发布,编译后的模块必须放在源代码目录,并且不要包含源代码模块。

下面是一些技巧:

1)你可以使用-O或者-OO参数减少编译后模块的大小。-O参数移除assert语句,-OO参数移除assert和__doc__串。由于有些程序依赖这些变量,所以在移除前你需要确认。优化后的模块后缀为.pyo而不是.pyc,并且更小。优化的效果在未来的版本中可能改变;

2)从.pyo文件或者.pyc文件加载的程序不会运行的比从.py文件加载的程序更快,唯一更快的只是加载速度;

3)compileall模块能将一个文件夹中的所有模块编译为.pyc文件(或者.pyo文件);

4)对这个过程更详细的细节请参考PEP 3147。

标准模块

Python提供了一个标准模块库,一些模块被构建到解释器中,一些操作并不是语言的核心操作但却被构建到解释器中,或者是为了效率,或者是为了访问操作系统指令,例如系统调用。这些模块依赖于底层系统,例如:winreg模块尽在Windows系统提供。有一个特殊的模块需要注意:sys,被构建到每一个Python解释器中。变量sys.ps1和sys.ps2定义了交互界面的一级和二级提示符:

>>> import sys
>>> sys.ps1
'>>> '
>>> sys.ps2
'... '
>>> sys.ps1 = 'C> '
C> print('Yuck!')
Yuck!
C>

注意这两个变量只有在解释器在交互模式才被定义。

sys.path定义了解释器的搜索路径,它的初始值为环境变量PYTHONPATH,如果PYTHONPATH未定义,则为内建的默认值。你能用标准的list方法来修改它:

>>> import sys
>>> sys.path.append('/ufs/guido/lib/python')

dir()函数

内建函数dir()用于查看模块定义了的名字,它返回排序后的字符串列表:

>>> import fibo
>>> dir(fibo)
['__builtins__', '__cached__', '__doc__', '__file__', '__initializing__', '__loader__', '__name__', '__package__', 'fib', 'fib2']

如果不带参数,则dir()返回你当前正在定义的模块定义的名字。

>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__', 'fibo', 'sys']

这些名字包括:变量、模块、函数等。

dir()不会返回内嵌函数和变量的名字,如果你想查看他们,他们被定义在标准模块builtins中:

>>> import builtins
>>> dir(builtins)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '_', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']

包是构建Python模块的命名空间的一个方法,在名称间使用逗号分隔,例如,模块名A.B表示包A下的子模块B。就像不同模块的作者不用担心全局变量名冲突一样,不同包的作者不用担心模块名的冲突。

假定你想实现一个模块集合(一个包),用于处理声音文件和数据。可能有多种不同的声音文件格式(通常通过扩展名区分,例如:.wav、.aiff、.au等),于是你需要创建和维护越来越多的模块,用于处理不同的文件格式。你也可能需要使用多种不同的操作处理声音数据(例如混合、增加回音、应用一个均衡器函数、创建一个人造立体效果等),于是你发现需要实现的模块越来越多,无穷无尽。下面是你可能采用的包结构:

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__变量,在后面描述。

包的用户可以导入独立的模块,例如:

import sound.effects.echo

这将加载子模块sound.effects.echo,它必须使用全名来访问:

sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)

另一个导入子模块的方法为:

from sound.effects import echo

这也导入子模块,但使用不必加前缀:

echo.echofilter(input, output, delay=0.7, atten=4)

你也可以直接导入需要的函数或者变量:

from sound.effects.echo import echofilter

这样你就可以直接使用子模块echo的函数echofilter():

echofilter(input, output, delay=0.7, atten=4)

注意当使用那个from package import item时,item可以是包的子模块(或子包),或者定义在包中的名字,例如函数、类或变量。import首先测试item是否在包中;如果没有,它假定它是一个模块并尝试加载它;如果失败,ImportError将被抛出。

当使用import item.subitem.subsubitem时,要求中间的条目必须是包,最后的条目可以是模块或者包,但不能是类、函数或者变量。

从包导入*

思考一下from sound.effects import *将发生什么?理想情况下,Python将查看包下的所有子模块,并导入他们。但是这样做会耗费大量的时间并且当子模块被明确的导入过时,可能会产生一些意想不到的副作用。

唯一的办法是包的作者提供明确的包的索引,import遵循下面的规则:如果包的__init__.py定义了子模块列表__all__,那么from package import *语句将导入__all__中包含的子模块。当包的新版本发布时,包的作者需要负责更新这个列表。例如,文件sound/effects/__init__.py中可能包含下面的代码:

__all__ = ["echo", "surround", "reverse"]

这意味着from sound.effects import *将导入sound包下的3个子模块。

如果__all__未被定义,from sound.effects import *语句不导入包sound.effects下的所有子模块到当前的命名空间;他仅确保包sound.effects被导入,并导入包中定义的所有名称。这包括被__init__.py定义的名称,也包括包的子模块定义的名称,包括那些已经被import加载的子模块。看下面的代码:

import sound.effects.echo
import sound.effects.surround
from sound.effects import *

在这个例子中,当from...import语句被执行时,echo和surround模块被导入当前的命名空间,因为他们被定义在sound.effects包中。

当你使用import *时,虽然仅会导入包的名称,这种做法在产品代码中任然被认为是糟糕的实践。

记住,from Package import specific_submodule是被推荐的使用方式,除非导入的模块需要使用来自不同包的具有相同名称的子模块。

包之间的引用

当包中包含子包,你能使用绝对路径来导入子包中的模块,例如:如果模块sound.filters.vocoder需要在sound.effects中用echo模块,他能通过from sound.effects import echo使用。

你也能使用相对路径导入,使用from module import name语句,一个点表示当前路径,两个点表示父目录。看surround的例子,你可以用:

from . import echo
from .. import formats
from ..filters import equalizer

注意相对路径导入是基于当前模块的名字,由于主模块的名字总是"__main__",如果模块想要被作为主模块,则必须使用绝对路径导入。

多目录的包

包支持一个特殊的属性__path__,这被初始化为包含__init__.py的目录名列表,该变量能被修改,修改后将影响后续对包中的子包和模块的查找。

时间: 2024-11-05 16:00:53

python12:模块的相关文章

分享老男孩自动化开发运维Python12期

本套教程共L33天,完整版!!! 目录: L001-老男孩教育-Python12期VIP视频-18节 0001-开课介绍.mp40002-同学互相介绍.mp40003-python简史介绍.mp40004-python3的新特性.mp40005-开发工具ide介绍.mp40006-helloworld程序.mp40007-变量与赋值.mp40008-用户交互.mp40009-条件判断与缩进.mp40010-循环控制.mp40011-循环次数限制.mp40012-常用数据类型.mp40013-字符

模块 一

一.os模块 os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口,多用于文件处理,控制文件和文件夹. 首先导入os 模块 import os 对文件进行操作 os.path.isfile(r' ') 判断是否为文件 os.remove(r' ') 删除文件 os.rename(r' ', r' ') 重命名文件 对文件夹进行操作 os.path.isdir() 判断是否为文件夹 os.mkdir(r' ') 创建文件夹 os.rmdir(r' ') 删除文件夹 os.listdir(

Day5 - 常用模块学习

本节大纲: 模块介绍(模块导入方法) time &datetime模块 random os sys shutil json & picle shelve xml处理 yaml处理 configparser hashlib subprocess logging模块 re正则表达式 模块,用一堆代码实现了某个功能的代码集合. 类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合.而对于一个复杂的功能来,可能需要多个函数才能完成(函数又

c# 无法加载xxx.dll 找不到指定的模块(如何指定文件夹)

如果直接放在项目运行目录,例如bin/debug可以直接加载,但是这样比较乱. 如果在放debug里面的一个文件夹里面,有可能会报错“无法加载xxx.dll 找不到指定的模块”. 如果路径写成这样就会报错 framework/linphone 解决方法:将/ 改成"\" framework\linphone

LEDAPS1.3.0版本移植到windows平台----HuCsm云掩膜模块

这个是2012年左右放在百度空间的,谁知百度空间关闭...转移到博客园. 最近项目用到3.1.2版本的LEDAPS,新版本的使用情况会在后续文章中慢慢丰富. HuCsm是将LEDAPS项目中的TM/ETM+大气校正流程系列算法中的云掩膜模块由linux系统移植到windows下的产物,代码本身改动不大,使用接口不变. 包含文件: HuCsm.exe hd423m.dll hm423m.dll 编译程序需要包含的静态库有: gctp.lib hdfeos.lib hd423m.lib hm423m

Python学习系列----第五章 模块

5.1 如何引入模块 在Python中用关键字import来引入某个模块,比如要引用模块math,就可以在文件最开始的地方用import math来引入.在调用math模块中的函数时,必须这样引用: 模块名.函数名 有时候我们只需要用到模块中的某个函数,只需要引入该函数即可,此时可以通过语句 from 模块名 import 函数名1,函数名2.... 5.2 如何定义自己的模块 在Python中,每个Python文件都可以作为一个模块,模块的名字就是文件的名字. 比如有这样一个文件test.py

Python:hashlib加密模块,flask模块写登录接口

hashlib模块 主要用于加密相关的操作,(比如说加密字符串)在python3的版本里,代替了md5和sha模块,主要提供 sha1, sha224, sha256, sha384, sha512 ,md5 这些加密方式 import  hashlib m = hashlib.md5()   #用md5加密的方式(md5加密后无法解密),创建一个md5的对象 m.update(b"Hello")  #b代表二进制字节bytes,把字符串hello转成字节,然后加密:用b给一个变量转换

python如何使用pymysql模块

Python 3.x 操作MySQL的pymysql模块详解 前言pymysql是Python中操作MySQL的模块,其使用方法和MySQLdb几乎相同.但目前pymysql支持python3.x而MySQLdb不支持3.x版本. 一.安装 pip3 install pymysql 二.pymysql方法 pymysql.connect()参数说明 参数 类型 说明 host str mysql服务器地址 port int mysql服务器端口号 user str 用户名 passwd str

微控工具xp模块-开发版[微信(wechat)二次开发模块]

http://repo.xposed.info/module/com.easy.wtool 微控工具xp模块-开发版[微信(wechat)二次开发模块] 基于xposed框架的微信二次开发模块,方便开发者用微信做一些扩展功能(如微信群发.多群直播等...) 目前支持功能: 发文本消息 发图片消息 发语音消息 发视频消息 获取微信好友列表 群列表 支持群发消息 支持消息转发(目前支持文本.图片.语音.视频.图文消息转发) 群管理功能(建群.加人.踢人.设置公告.改群名.退群.解散群) [注:本模块