上一节(2.7对象模型)|下一节(3.2函数深入)3.1脚本在本节中,我们将深入研究编写Python脚本的约定。什么是脚本?脚本是运行和终止一系列语句的程序。#program.pystatement1statement2statement3...到目前为止,我们主要是在编写脚本。问题如果您编写有用的脚本,它的特性和功能将会增加。您可能希望将其应用于相关问题。随着时间的推移,它可能会成为一个关键的应用程序。如果您不注意,它可能会变得一团糟。所以让我们组织起来。定义变量名必须在使用前定义。defsquare(x):returnx*xa=42b=a+2#Requiresthat`a`isdefinedz=square(b)#Requires`square`and`b`tobedefined顺序很重要。几乎总是将变量和函数定义放在顶部附近。定义函数是将与单个任务相关的所有代码放在一个地方的好主意。这可以使用函数来实现:defread_prices(filename):prices={}withopen(filename)asf:f_csv=csv.reader(f)forrowinf_csv:prices[row[0]]=float(row[1])退货价格功能还可以简化重复操作。oldprices=read_prices('oldprices.csv')newprices=read_prices('newprices.csv')什么是函数?函数是命名的语句序列。deffuncname(args):statementstatement...returnresult任何Python语句都可以在函数内部使用。deffoo():importmathprint(math.sqrt(2))help(math)Python中没有特殊的语句(方便记忆)。函数定义函数可以按任何顺序定义。deffoo(x):bar(x)defbar(x):statements#ORdefbar(x):statementsdeffoo(x):bar(x)在程序执行期间实际使用(调用)函数之前必须对其进行定义.foo(3)#foo必须已经定义从风格上讲,以自下而上的方式定义函数可能更常见。自下而上的样式函数用作构建块。更小/更简单的块优先。#myprogram.pydeffoo(x):...defbar(x):...foo(x)#定义如上...defspam(x):...bar(x)#定义如上...spam(42)#使用函数的代码出现在最后后面的函数是建立在前面函数的基础上的。同样,这只是风格问题。上面程序中唯一重要的事情是对spam(42)的调用是在最后一步。功能设计理想情况下,功能应该是一个黑盒子。它们应该只对输入进行操作并避免全局变量和奇怪的副作用。主要目标:模块化和可预测性。文档字符串以文档字符串的形式包含文档是一种很好的做法。文档字符串是紧跟在函数名称之后的字符串。它们用于help()函数、IDE和其他工具。defread_prices(filename):'''从名称的CSV文件中读取价格,价格数据'''prices={}withopen(filename)asf:f_csv=csv.reader(f)forrowinf_csv:prices[row[0]]=float(row[1])returnprices一个好的文档字符串实践是写一个简短的句子来总结函数的作用。如果需要更多信息,请包括一个简短的使用示例和更详细的参数说明。类型注释还可以向函数定义添加可选的类型提示。defread_prices(filename:str)->dict:'''从名称的CSV文件中读取价格,价格数据'''prices={}withopen(filename)asf:f_csv=csv.reader(f)forrow在f_csv中:prices[row[0]]=float(row[1])returnpricesprompt对操作没有任何作用。它们纯粹是信息性的。但是,IDE、代码检查器和其他工具可能会使用它做更多的事情。练习在第2节中,您编写了一个名为report.py的程序,它打印出一份显示股票投资组合表现的报告。该程序包含一些功能。例如:#report.pyimportcsvdefread_portfolio(filename):'''将股票投资组合文件读入字典列表,其中包含键名、股票和价格。'''portfolio=[]withopen(filename)asf:rows=csv.reader(f)headers=next(rows)forrowinrows:record=dict(zip(headers,row))stock={'name':record['name'],'shares':int(record['shares']),'price':float(record['price'])}portfolio.append(stock)returnportfolio...然而,该程序的某些部分只是执行一系列脚本计算。这些代码出现在程序的末尾。示例:...#输出reportheaders=('Name','Shares','Price','Change')print('%10s%10s%10s%10s'%headers)print(('-'*10+'')*len(headers))forrowinreport:print('%10s%10d%10.2f%10.2f'%row)...在这个练习中我们使用函数来组织程序Theorganizationmakestheprogram更健壮。练习3.1:将程序构建为函数集合修改report.py程序,使所有主要操作(包括计算和输出)都由函数集合执行。具体来说:创建打印报告的函数print_report(report)。修改程序的最后一部分,使其只是一系列函数调用,不执行其他操作。练习3.2:为程序执行创建一个顶层函数将程序的最后部分打包成一个函数portfolio_report(portfolio_filename,prices_filename)。让程序运行,以便下面的函数调用像以前一样创建报告。portfolio_report('Data/portfolio.csv','Data/prices.csv')在最终版本中,程序只不过是一系列函数定义,最终调用单个函数portfolio_report()(它完成所有步骤).通过将程序转换为单个函数,可以很容易地在不同的输入上运行它。例如,在运行程序后交互地尝试这些语句:>>>portfolio_report('Data/portfolio2.csv','Data/prices.csv')...查看输出...>>>files=['Data/portfolio.csv','Data/portfolio2.csv']>>>fornameinfiles:print(f'{name:-^43s}')portfolio_report(name,'Data/prices.csv')print()...查看输出...>>>说明Python使得在包含一系列语句的文件中编写相对非结构化的脚本变得容易。一般来说,尽可能利用函数通常会更好。在某些时候脚本会变大,我们希望它更有条理。此外,一个鲜为人知的事实是,如果您使用函数,Python运行速度会更快一些。目录|上一节(2.7对象模型)|NextSection(3.2In-depthFunctions)注:完整翻译见https://github.com/codists/practical-python-zh
