上一节(3.3错误检查)|下一节(3.5主模块)3.4模块本节介绍模块的概念以及如何使用跨多个文件的函数。模块和导入任何Python源文件都是一个模块。#foo.pydefgrok(a):...defspam(b):...import语句加载并执行一个模块。#program.pyimportfooa=foo.grok(2)b=foo.spam('Hello')...命名空间模块是命名值的集合,有时称为命名空间。名称是源文件中定义的所有全局变量和函数。导入后,模块名称用作前缀。因此,它被称为命名空间。importfooa=foo.grok(2)b=foo.spam('Hello')...模块名直接绑定到文件名(foo->foo.py)。全局定义使用在全局范围内定义的任何内容填充模块的名称空间。考虑定义相同变量x的两个模块。#foo.pyx=42defgrok(a):...#bar.pyx=37defspam(a):...在这种情况下,x指向不同的变量。一个是foo.x,另一个是bar.x。不同的模块可以使用相同的名称,名称之间不会冲突。模块是隔离的。将模块视为环境模块为模块内定义的所有代码构成一个封闭环境。#foo.pyx=42defgrok(a):print(x)全局变量总是绑定到封闭模块(同一个文件),每个源文件都是它自己的小宇宙。模块执行当一个模块被导入时,模块中的所有语句都会依次执行,直到到达文件末尾。模块命名空间的内容都是在执行过程结束时仍然定义的全局名称。如果您有在全局范围内执行任务的脚本语句(例如打印、创建文件等),您将在导入模块时看到它们运行。importas语句可以在导入时更改模块的名称:importmathasmdefrectangular(r,theta):x=r*m.cos(theta)y=r*m.sin(theta)returnx,y它的作用与正常导入相同,只是重命名模块。fromimport语句fromimport语句从模块中选择符号并使它们在本地可访问。frommathimportsin,cosdefrectangular(r,theta):x=r*cos(theta)y=r*sin(theta)returnx,y这允许使用模块的某些部分而无需键入模块前缀。这对于经常使用的名称非常有用。导入说明导入的变化不会改变模块的工作方式。importmath#vsimportmathasm#vsfrommathimportcos,sin...具体来说,import始终执行整个文件,模块保持隔离环境。importmoduleas语句仅在本地更改名称。在幕后,frommathimportcos,sin语句仍然加载完整的数学模块。导入完成后,它只是将cos和sin名称从模块复制到本地名称空间中。模块加载每个模块只加载和执行一次。注意:重复导入只返回对先前加载模块的引用sys.modules是所有加载模块的字典。>>>importsys>>>sys.modules.keys()['copy_reg','__main__','site','__builtin__','encodings','encodings.encodings','posixpath',...]>>>注意:在修改模块的源代码后重复导入语句时,会出现一个常见的混淆。由于模块缓存sys.modules,重复导入总是返回以前加载的模块——即使发生了更改。将修改后的代码加载到Python中最安全的方法是退出并重新启动解释器。定位模块在搜索模块时,Python从路径列表(sys.path)中查找。>>>importsys>>>sys.path['','/usr/local/lib/python36/python36.zip','/usr/local/lib/python36',...]当前工作目录是通常首先。模块搜索路径如前所述,sys.path包含搜索路径。可根据需要手动调整。importsyssys.path.append('/project/foo/pyfiles')也可以通过环境变量添加搜索路径。%envPYTHONPATH=/project/foo/pyfilespython3Python3.6.0(默认,2017年2月3日,05:53:21)[GCC4.2.1兼容AppleLLVM8.0.0(clang-800.0.38)]>>>importsys>>>sys.path['','/project/foo/pyfiles',...]大多数情况下不需要手动调整模块搜索路径。但是,如果您尝试导入的Python代码位于特殊位置,或者无法从当前工作目录轻松访问,那么您将需要手动调整搜索路径。练习因为本练习涉及模块,所以确保您在正确的环境中运行Python至关重要。模块通常会给编程新手带来问题,无论是当前工作目录还是Python路径设置。对于本课,假设您在Work/目录中编写所有代码。为获得最佳结果,您还应确保在Work/目录中运行解释器。否则,您需要确保将practical-python/Work添加到sys.path。练习3.11:模块导入在第3节中,我们创建了一个通用目标函数parse_csv()来解析CSV数据文件的内容。现在,让我们看看如何在其他程序中使用这个函数。首先,启动一个新的shell窗口并切换到放置所有文件的目录。我们要导入它们。启动Python交互模式。bash%python3Python3.6.1(v3.6.1:69c0db5050,Mar212017,01:21:04)[GCC4.2.1(AppleInc.build5666)(dot3)]ondarwinType"help","copyright","credits"或"license"获取更多信息。>>>当Python交互模式启动时,尝试导入一些以前编写的程序。您应该看到与以前相同的输出。只是强调一下,导入模块运行模块中的代码。>>>importbounce...watchoutput...>>>importmortgage...watchoutput...>>>importreport...watchoutput...>>>如果没有代码运行,可能是因为在错误的目录中运行Python。现在,尝试导入fileparse模块并获得帮助。>>>importfileparse>>>help(fileparse)...查看输出...>>>dir(fileparse)...查看输出...>>>尝试使用fileparse模块读取一些数据:>>>portfolio=fileparse.parse_csv('Data/portfolio.csv',select=['name','shares','price'],types=[str,int,float])>>>portfolio...查看输出...>>>pricelist=fileparse.parse_csv('Data/prices.csv',types=[str,float],has_headers=False)>>>pricelist...查看输出。..>>>prices=dict(pricelist)>>>prices...查看输出...>>>prices['IBM']106.11>>>尝试导入一个函数,这样你就不必包含模块名称:>>>fromfileparseimportparse_csv>>>portfolio=parse_csv('Data/portfolio.csv',select=['name','shares','price'],types=[str,int,float])>>>portfolio...查看输出...>>>练习3.12:使用库模块在第2节中,编写了程序report.py以生成如下所示的股票报告:NameSharesPriceChange---------------------------------------AA1009.22-22.98IBM50106.2815.18CAT15035.46-47.98MSFT20020.89-30.34GE9513.48-26.89MSFT5020.89-44.21IBM100106.2835.84对这个程序进行修改,以便使用fileparse模块中的函数完成所有输入文件处理为此,将fileparse作为模块导入并修改read_portfolio()和read_prices()函数以便使用parse_csv()函数。在开始本练习时,使用交互式示例作为指南。之后,您应该能够获得与之前完全相同的输出。练习3.14:使用更多库导入在第1节中,您编写了一个程序pcost.py,它读取股票投资组合并计算费用。>>>importpcost>>>pcost.portfolio_cost('Data/portfolio.csv')44671.15>>>请修改pcost.py文件,使其使用report.read_portfolio()函数。说明当你完成练习时,你应该有三个程序。包含通用函数parse_csv()的fileparse.py程序。report.py程序用于生成报告并包含read_portfolio()和read_prices()函数。最后,使用report.py程序中编写的read_portfolio()函数来计算股票投资组合成本的pcost.py程序。目录|上一节(3.3错误检查)|NextSection(3.5MainModule)注:完整翻译见https://github.com/codists/practical-python-zh
