当前位置: 首页 > 后端技术 > Python

【Python1-14】Python动手教程-函数高级用法详解

时间:2023-03-25 19:38:43 Python

作者|弗拉德来源|,其中可能包含名称、数字或更复杂的对象(例如字典)。当一个列表被传递给一个函数时,该函数可以直接访问它的内容。下面使用函数来提高处理列表的效率。假设我们有一个用户列表,我们想问候他们每个人。以下示例将姓名列表传递给名为greet_users()的函数,该函数向列表中的每个人致意:defgreet_users(names):"""Sendasimplegreetingtoeachuserinthelist"""fornameinnames:msg="你好,"+name.title()+"!"print(msg)usernames=['hannah','ty','margot']greet_users(usernames)我们将greet_users()定义为接受名称列表并将它们存储在形式参数名称中。此函数遍历接收到的列表并为其中的每个用户打印问候语。然后我们定义一个用户列表——用户名,并调用greet_users(),将这个列表传递给它:你好,汉娜!你好,泰!你好,玛格特!输出完全符合预期,每个用户都看到了个性化的个性化问候语。每当您想问候一组用户时调用此函数。在函数中修改列表一旦列表被传递给函数,它就可以被函数修改。在函数内对该列表所做的任何修改都是永久性的,这使您可以高效地处理大量数据。认识一家根据用户提交的设计制作3D打印模型的公司。需要打印的设计存储在一个列表中,打印后移动到另一个列表。下面是不使用函数来模拟这个过程的代码:#首先创建一个包含一些要打印的设计的列表unprinted_designs=['iphonecase','robotpendant','dodecahedron']completed_models=[]#模拟打印每个设计,直到有nounprinteddesigns#打印每个设计后,将其移动到列表completed_modelswhileunprinted_designs:current_design=unprinted_designs.pop()#模拟根据设计制作3D打印模型的过程print("Printingmodel:"+current_design)completed_models.append(current_design)#显示所有打印模型print("\n以下模型已经打印:")forcompleted_modelincompleted_models:print(completed_model)这个程序首先创建一个模型需要打印的设计列表,同时创建一个称为completed_models的空列表,每个设计打印都将移至此列表。只要列表unprinted_designs中有设计,while循环模拟打印设计的过程:从列表的末尾删除一个设计,将其存储在变量current_design中,显示一条消息表明正在打印当前设计,然后将设计添加到列表completed_models中。循环结束后,所有已经打印出来的设计都显示出来:打印模型:dodecahedron打印模型:robotpendant打印模型:iphonecase已经打印的模型如下:dodecahedronrobotpendantiphonecase为了重组这段代码,我们可以写两个函数,每个函数都有做一个特定的工作。大多数代码与以前相同,只是效率更高。第一个函数将负责打印设计,而第二个函数将概述打印了哪些设计:defprint_models(unprinted_designs,completed_models):"""模拟打印每个设计,直到没有未打印的设计打印每个设计完成后,movethemtothelistcompleted_models"""whileunprinted_designs:current_design=unprinted_designs.pop()#模拟根据设计制作3D打印模型的过程print("Printingmodel:"+current_design)completed_models.append(current_design)defshow_completed_models(completed_models):"""显示所有打印模型"""print("\n已打印以下模型:")forcompleted_modelincompleted_models:print(completed_model)unprinted_designs=['iphonecase','robotpendant','dodecahedron']completed_models=[]print_models(unprinted_designs,completed_models)show_completed_models(completed_models)首先,我们定义函数print_models(),它包含两个参数:一个要打印的设计列表和打印的模型列表。给定这两个列表,此函数模拟打印每个设计的过程:一个接一个,设计从未打印设计列表中取出并添加到打印模型列表中。然后,我们定义了函数show_completed_models(),它包含一个形式参数:打印模型列表。鉴于此列表,函数show_completed_models()显示打印出的每个模型的名称。该程序的输出与没有函数的版本相同,但更有条理。完成大部分工作的代码已移至两个函数中,以使主程序更易于理解。看看主程序就知道,这个程序的功能就简单多了:show_completed_models(completed_models)我们创建了一个未打印设计列表和一个空列表来存储打印模型。接下来,因为我们已经定义了两个函数,所以我们只需要调用它们并传入正确的参数。我们调用print_models()并传递给它两个列表;正如预期的那样,print_models()模拟打印设计的过程。接下来,我们调用show_completed_models(),将打印模型列表传递给它,以便它可以指示打印了哪些模型。描述性的函数名称使阅读代码的人可以理解,即使没有任何注释。该程序比没有功能的版本更易于扩展和维护。如果稍后需要打印其他设计,只需再次调用print_models()即可。如果我们发现需要修改打印代码,只需要修改这段代码一次,就可以影响所有调用该函数的地方;这种修改比必须单独修改程序中的多个地方更有效。该程序还展示了每个功能只应负责一项特定工作的想法。第一个功能打印每个设计,而第二个功能显示打印的模型;这比使用一个函数来完成两个工作要好。在写一个函数的时候,如果你发现它执行的任务太多,试着把代码分成两个函数。不要忘记一个函数总是可以调用另一个函数,这有助于将复杂的任务分解为一系列步骤。传递任意数量的参数有时,您事先并不知道一个函数需要接受多少个参数。幸运的是,Python允许函数从调用语句中收集任意数量的参数。例如,考虑一个制作比萨饼的函数,该比萨饼可以接受多种配料,但您无法预先确定客户将订购多少配料。下面的函数只有一个形参*toppings,但是无论调用语句提供了多少个实参,这个形参都会把它们全部收集起来:defmake_pizza(*toppings):"""打印所有由customer"""print(toppings)make_pizza('pepperoni')make_pizza('mushrooms','greenpeppers','extracheese')形式参数名称*toppings中的星号告诉Python创建一个名为toppings的空元组,并且将接收到的所有值都打包到这个元组中。函数体中的print语句演示了Python可以通过生成输出来处理用一个值调用函数的情况,以及用三个值调用函数的情况。它以类似的方式处理不同的调用,注意Python将参数包装到一个元组中,即使函数只接收一个值:('pepperoni',)('mushrooms','greenpeppers','extracheese')现在,我们可以用循环遍历浇头列表并描述客户订购的比萨饼来替换此打印语句:defmake_pizza(*toppings):"""要制作的比萨饼摘要"""print("\nMaking带有以下配料的比萨饼:")fortoppingintoppings:print("-"+topping)make_pizza('pepperoni')make_pizza('mushrooms','greenpeppers','extracheese')这个函数优雅地处理它是否它接收一个或三个值:使用以下配料制作比萨饼:-意大利辣香肠使用以下配料制作比萨饼:-蘑菇-青椒-额外的奶酪无论接收到的函数如何无论实际参数有多少,该语法都有效.在模块中存储函数函数的优点之一是它们允许您将代码块与主程序分开。通过给函数一个描述性的名称,主程序变得更容易理解。您可以更进一步,将函数存储在称为模块的单独文件中,然后将模块导入主程序。import语句允许模块中的代码在当前运行的程序文件中使用。通过将函数存储在单独的文件中,可以隐藏程序代码的细节,专注于程序的高层逻辑。这也允许您在许多不同的程序中重用函数。通过将函数存储在单独的文件中,这些文件可以与其他程序员而不是整个程序共享。了解如何导入函数还可以让您使用其他程序员编写的函数库。导入模块的方式有很多种,下面分别简单介绍一下。导入整个模块要使函数可导入,必须首先创建模块。模块是扩展名为.py的文件,其中包含要导入到程序中的代码。让我们创建一个包含函数make_pizza()的模块。为此,我们删除文件pizza.py中除函数make_pizza()之外的所有代码:defmake_pizza(size,*toppings):"""Summaryofthepizzatobemade"""print("\nMakinga"+str(size)+"-inchpizzawiththefollowingtoppings:")fortoppingintoppings:print("-"+topping)接下来,我们在与pizza.py文件相同的目录中创建另一个名为making_pizzas.py的文件,这个文件导入刚刚创建的模块,然后调用make_pizza()两次:importpizzapizza.make_pizza(16,'pepperoni')pizza.make_pizza(12,'mushrooms','greenpeppers','extracheese')当Python读取这个文件,importpizza行告诉Python打开文件pizza.py并将其中的所有函数复制到程序中。你看不到复制的代码,因为Python在程序运行时正在幕后复制代码。您只需要知道在making_pizzas.py中,您可以使用pizza.py中定义的所有函数。要调用导入模块中的函数,请指定导入模块的名称pizza和函数名称make_pizza(),并用句点分隔它们。这些代码的输出与未导入模块的原始程序相同:制作一个16英寸的比萨饼,配料如下:-意大利辣香肠制作一个12英寸的比萨饼,配料如下:-蘑菇-青椒-额外的奶酪这一种导入方式:只需要写一个导入语句,在里面指定模块名,就可以在程序中使用模块中的所有功能。如果您使用此导入语句导入名为module_name.py的整个模块,则可以使用以下语法使用任何函数:module_name.function_name()导入特定函数您还可以导入模块中的特定函数,此导入的语法方法如下:frommodule_nameimportfunction_name通过用逗号分隔函数名称,您可以从模块中导入任意数量的函数:frommodule_nameimportfunction_0,function_1,function_2对于前面的making_pizzas.py示例,如果您只想导入要使用的函数,代码如下所示:frompizzaimportmake_pizzamake_pizza(16,'pepperoni')make_pizza(12,'mushrooms','greenpeppers','extracheese')使用此语法,调用函数无需使用句点。由于我们在import语句中显式导入了函数make_pizza(),因此我们只需要在调用它时指定它的名称即可。使用as为函数指定别名如果要导入的函数的名称可能与程序中现有的名称冲突,或者函数的名称太长,您可以指定一个简短且唯一的别名-另一个名称功能,类似于昵称。要给一个函数这个特殊的昵称,你需要在导入它的时候这样做。函数make_pizza()在下面被赋予别名mp()。这是在导入语句中使用make_pizzaasmp实现的,关键字as将函数重命名为您提供的别名:frompizzaimportmake_pizzaasmpmp(16,'pepperoni')mp(12,'mushrooms','greenpeppers','extracheese')上面的import语句将函数make_pizza()重命名为mp();在这个程序中,每当需要调用make_pizza()时,可以简写为mp(),Python会运行make_pizza()以避免与这个程序可能包含的函数make_pizza()混淆。指定别名的一般语法如下:frommodule_nameimportfunction_nameasfn使用as为模块指定别名您也可以为模块指定别名。通过为模块分配一个简短的别名(例如为模块pizza分配别名p),您可以更轻松地调用模块中的函数。与pizza.make_pizza()相比,p.make_pizza()更简洁:importpizzaaspp.make_pizza(16,'pepperoni')p.make_pizza(12,'mushrooms','greenpeppers','extracheese')上面的import语句为模块pizza分配了别名p,但模块中所有函数的名称保持不变。在调用函数make_pizza()时,可以将代码写成p.make_pizza(),而不是pizza.make_pizza(),这样不仅让代码更加简洁,还可以让你不再关注模块名,专注于描述性函数名称。这些函数名清楚地表明了函数的作用,而且它们对于理解代码比模块名更重要。为模块指定别名的一般语法如下:importmodule_nameasmn导入模块中的所有函数使用星号(*)运算符让Python导入模块中的所有函数:frompizzaimport*make_pizza(16,'pepperoni')make_pizza(12,'mushrooms','greenpeppers','extracheese')import语句中的星号告诉Python将模块pizza中的每个函数复制到这个程序文件中。由于每个函数都是导入的,因此无需使用句号即可按名称调用。但是,在使用非自己编写的大模块时最好不要使用这种导入方式:如果模块中有与自己项目中使用的函数同名的函数,可能会导致意想不到的结果:Python可能会遇到多个具有相同名称的函数或变量,从而覆盖函数,而不是单独导入所有函数。最佳做法是只导入您需要使用的函数,或者导入整个模块并使用句点符号。这使代码更清晰,更易于阅读和理解。之所以在这里介绍这种导入方式,是因为大家在阅读别人写的代码时,如果遇到类似如下的导入语句,可以理解一下:frommodule_nameimport*Functionwritingguide在写函数的时候,需要保留一个几件事情记在心里细节。应为函数提供描述性名称,仅使用小写字母和下划线。描述性名称有助于您和其他人理解代码的作用。命名模块时也应遵循上述约定。每个函数都应该包含一个注释,以文档字符串格式紧跟在函数定义之后,简要描述它的作用。一个文档完善的函数允许其他程序员通过阅读文档字符串中的描述来简单地使用它:他们可以完全相信代码按照描述工作;只要他们知道函数的名称、所需的参数和返回值的类型,他们就可以在自己的程序中使用它。为形参指定默认值时,等号两边不能有空格:deffunction_name(parameter_0,parameter_1='defaultvalue')对于函数调用中的关键字参数,也应遵循此约定:function_name(value_0,parameter_1='value')官方建议代码行长度不要超过79个字符,这样只要编辑器窗口适中,就能看到整行代码。如果形参较多,函数定义长度超过79个字符,可以在函数定义中输入左括号按回车键,在下一行按两次Tab键,这样形参列表并且只有一层的缩进与函数体分开。大多数编辑器会自动将后续参数列表行与您为第一个参数列表行指定的相同缩进对齐:deffunction_name(parameter_0,parameter_1,parameter_2,parameter_3,parameter_4,parameter_5):functionbody...如果程序或模块包含多个功能,两个空行可以用来分隔相邻的功能。这将使您更容易知道上一个函数在哪里结束以及下一个函数从哪里开始。所有导入语句都应放在文件的开头,唯一的例外是在文件开头使用注释来描述整个程序。