模块与包是任何大型程序的核心,就连Python安装程序本身也是一个包。本章重点涉及有关模块和包的常用编程技术,例如如何组织包、把大型模块分割成多个文件、创建命名空间包。同时,也给出了让你自定义导入语句的秘籍。
模块
模块简介
模块是一个包含Python定义和语句的文件。文件名就是模块名后跟文件后缀 .py 在一个模块内部,模块名(作为一个字符串)可以通过全局变量 name 的值获得。
比如你可以创建一个 myfiles.py 的模块,简单来说模块也就是一个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模块的路径。
调用模块里面的功能有两种方法:
- 直接调用这个py文件(这个要求就是模块不大,里面功能相对少很多)
- 调用py文件中某一个函数或者参数(这种要求就是我们调用模块的一部分,不是要求调用整个模块)
还有一种就是from fac_1 import *
,但这个*号里面要在__all__里面先声明。
简化函数名
如果你想经常使用某个函数,你可以把它赋值给一个局部变量
fib = fibo.fib
fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
from fibo import *
fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
这会调入所有非以下划线(_)开头的名称。 在多数情况下,Python程序员都不会使用这个功能,因为它在解释器中引入了一组未知的名称,而它们很可能会覆盖一些你已经定义过的东西。
注意通常情况下从一个模块或者包内调入 * 的做法是不太被接受的, 因为这通常会导致代码的可读性很差。不过,在交互式编译器中为了节省打字可以这么用。
简化模块名
如果模块名称之后带有 as,则跟在 as 之后的名称将直接绑定到所导入的模块。
from fibo import fib as fibonacci
fibonacci(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
编译过的Python文件
python文件的后缀名有.py和pyc这两种,但pyc一般是编译过的Python文件,这样为的是提高程序的运行速率,下次调用这个py文件就不需要编译,相对来说速率提升了很多,下面我引用了python官方文档的一段话作为参考。
为了加速模块载入,Python在 pycache 目录里缓存了每个模块的编译后版本,名称为 module.version.pyc ,其中名称中的版本字段对编译文件的格式进行编码; 它一般使用Python版本号。例如,在CPython版本3.3中,spam.py的编译版本将被缓存为 pycache/spam.cpython-33.pyc。此命名约定允许来自不同发行版和不同版本的Python的已编译模块共存。
Python根据编译版本检查源的修改日期,以查看它是否已过期并需要重新编译。这是一个完全自动化的过程。此外,编译的模块与平台无关,因此可以在具有不同体系结构的系统之间共享相同的库。
Python在两种情况下不会检查缓存。首先,对于从命令行直接载入的模块,它从来都是重新编译并且不存储编译结果;其次,如果没有源模块,它不会检查缓存。为了支持无源文件(仅编译)发行版本, 编译模块必须是在源目录下,并且绝对不能有源模块。
模块我大致介绍到这里了,有兴趣的可以网上多查阅一下相关资料。
包
多个功能相似的模块可以组织成一个包, Python中的模块包括系统模块、第三方模块和用户自定义模块。它们实质上是以.py为扩展名的Python文件 。
包相对一个封装的过程,把多个py文件封装在一起,按照一定的目录格式生成,代码组织成由很多分层模块构成的包。封装成包是很简单的。在文件系统上组织你的代码,并确保每个目录都定义了一个__init__.py文件。包是Python引入的分层次的文件目录结构,它定义了一个由 模块及子包,和子包下的子包等组成的 Python 的应用环境。 引入了包以后,只要顶层的包名不与别人冲突,那所有模块都不会与别人冲突。
模块和包最大区别就是__init__.py文件,这个是包的标志。每一个Python的包目录下面都会有名为__init__.py的特殊文件, 该文件可以为空文件,但是必须存在,它表明这个目录不是普通的目录结构,而是一个包,里面包含模块。
包的分层结构示范
graphics/
__init__.py
primitive/
__init__.py
line.py
fill.py
text.py
formats/
__init__.py
png.py
jpg.py
下面我简单介绍一下Python包里面几个py文件。
setup.py
setup主要就是对你的包一个介绍和说明。
__init__文件介绍
init_.py 文件的作用是将文件夹变为一个Python模块,Python 中的每个模块的包中,都有__init__.py 文件。
通常__init__.py 文件为空,但是我们还可以为它增加其他的功能。我们在导入一个包时,实际上是导入了它的__init__.py文件。这样我们可以在__init__.py文件中批量导入我们所需要的模块,而不再需要一个一个的导入。
# __init__.py
import re
import urllib
import sys
import os
# a.py
import package
print(package.re, package.urllib, package.sys, package.os)#注意这里访问__init__.py文件中的引用文件,需要加上包名。
__init__.py中还有一个重要的变量,__all__, 它用来将模块全部导入。
################
# __init__.py
__all__ = ['os', 'sys', 're', 'urllib']
# a.py
from package import * #这时就会把注册在__init__.py文件中__all__列表中的模块和包导入到当前文件中来。
可以了解到,__init__.py主要控制包的导入行为。
通常__init__.py 文件为空,但是我们还可以为它增加其他的功能。我们在导入一个包时,实际上是导入了它的__init__.py文件。这样我们可以在__init__.py文件中批量导入我们所需要的模块,而不再需要一个一个的导入。
然后我们运行过你包里面的模块代码后会生成一个pyc文件,就是我上面说的编译后的文件,它的作用主要就是加快程序运行速度。
实例
我建一个简单的包,主要包含三个文件,setup.py和__init__ .py文件,以及我们的模块,大家可以看一下我的,虽然很low,主要也就是写给大家熟悉一下。
1.setup.py
from distutils.core import setup
setup(
name = 'zf-first_package',
version = '1.0.0',
keywords = ('simple', 'test'),
description = 'just a simple test',
author = 'zf',
author_email = '2063767947@qq.com',
py_modules =['test1.fac_1']
)
2.init .py文件
import re
import urllib
import sys
import os
import random
__all__ = ['os', 'sys', 're', 'urllib','random']
3.模块文件
#import urllib.parse
import numpy as np
#import random
__all__ =['hello_1','my_add','p_1']#__all__变量控制那些功能可以用*导入
def my_add(x,y):
return x+y
pipi = 3.0
p_1 =2
def hello_1():
print("hello world!")
if __name__ =='__main__':
print('This is my frist model')
print('This i so badly package')
print('__name__==',__name__)
def keyword_url(str1,encoding):
"""这个函数用来将中文转为网页对应的关键词编码,调用的是urllib包中的函数"""
a = urllib.parse.quote(str1.encode(encoding))
return a
def url_keyword(str1):
'''
解码作用,将网站的关键词编码转化为中文,也是调用urllib包中的一个函数
'''
a =urllib.parse.unquote(str1)
return a
def str1_fac(str1):
'''字符串逆序输出'''
b = str1[::-1]
return b
def my_fac(num):
'''求阶乘'''
s = 1
for i in range(1,num+1):
s*=i
return s
def loadData(fileName,ratio):
'''读取数据函数,输入为数据文件名和训练、测试切分比率,返回为list类型的训练数据集和测试数据集'''
'''这个针对的是txt文档,fileName文件路径名,ratio文件划分比例'''
trainingData=[]
testData=[]
with open(fileName) as txtData:
lines=txtData.readlines()
for line in lines:
lineData=line.strip().split(',') #去除空白和逗号“,”
if random.random()<ratio: #数据集分割比例
trainingData.append(lineData) #训练数据集列表
else:
testData.append(lineData) #测试数据集列表
return trainingData,testData
三引号括起来相当于是一个help()文档,就像我们平时说的那个help(),我们不知道一个函数的用法,help()就是起到这个作用。
最后模块和包就大致介绍到这里了,想了解更多的可以网上查一下资料。