函数(二)
传递列表
向函数传递列表很有用,这种列表包含的可能是名字、数字或更复杂的对象(如字典)。将列表传递给函数后,函数就能直接访问其内容。
代码示例:
>>>def greet_users(names): #greet_users定义为接受名字列表,并存储到names中
"""向列表中的每位用户都发出简单的问候"""
for name in names:
msg = "Hello, " + name + "!"
print(msg)
>>>usernames = ['Hannah', 'Ty', 'Margot'] #定义性的用户列表
>>>greet_users(usernames) #调用greet_users()
传入一个列表,进行循环遍历打印,然后得到如下结果。
运行结果:
Hello, Hannah!
Hello, Ty!
Hello, Margot!
在函数中修改列表
将列表传递给函数后,函数就可对其进行修改。在函数中对这个列表所做的任何修改都是永久性的,这让你能够高效地处理大量的数据。
下面是在不使用函数
的情况下模拟3D打印过程的代码:
# 首先创建一个列表,其中包含一些要打印的设计
unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron']
completed_models = []
# 模拟打印每个设计,直到没有未打印的设计为止
# 打印每个设计后,都将其移到列表completed_models中
while unprinted_designs:
current_design = unprinted_designs.pop()
#模拟根据设计制作3D打印模型的过程
print("打印 model: " + current_design)
completed_models.append(current_design)
# 显示打印好的所有模型
print("\n以下是打印型号:")
for completed_model in completed_models:
print(completed_model)
输出结果:
打印 model: dodecahedron
打印 model: robot pendant
打印 model: iphone case
以下是打印型号:
dodecahedron
robot pendant
iphone case
为重新组织这些代码,我们可编写两个函数
,每个都做一件具体的工作。大部分代码都与原来相同,只是效率更高。第一个函数将负责处理打印设计的工作,而第二个将概述打 印了哪些设计:
def print_models(unprinted_designs, completed_models):
"""
模拟打印每个设计,直到没有未打印的设计为止
打印每个设计后,都将其移到列表completed_models中
"""
while unprinted_designs:
current_design = unprinted_designs.pop()
# 模拟根据设计制作3D打印模型的过程
print("Printing model: " + current_design)
completed_models.append(current_design)
def show_completed_models(completed_models):
"""显示打印好的所有模型"""
print("\nThe following models have been printed:")
for completed_model in completed_models:
print(completed_model)
unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron']
completed_models = []
print_models(unprinted_designs, completed_models)
show_completed_models(completed_models)
输出结果:
Printing model: dodecahedron
Printing model: robot pendant
Printing model: iphone case
The following models have been printed:
dodecahedron
robot pendant
iphone case
禁止函数修改列表
将列表的副本传递给函数就可以实现没有修改列表。切片表示法[:]
创建列表的副本。语法如下:
function_name(list_name[:])
传递任意数量的实参
利用*
定义为一个空元组就可以将所有传入的实参都进行打印。例如:
>>> def make_pizza(*toppings): #利用*定义一个名为toppings空元组,将收到的所有值都封装到这个元组中
"""打印顾客点的所有配料"""
print(toppings)
>>> make_pizza('pepperoni')
>>> make_pizza('mushrooms', 'green peppers', 'extra cheese')
输出结果:
('pepperoni',)
('mushrooms', 'green peppers', 'extra cheese')
无论传入多少值都可以被打印出来。
现在,我们可以将这条print 语句替换为一个循环,对配料列表进行遍历,并对顾客点的比萨进行描述:
>>> def make_pizza (*toppings):
"""概述要制作的披萨"""
print("\n制作披萨的所有配料:")
for topping in toppings:
print("-"+topping)
>>> make_pizza('pepperoni')
>>> make_pizza('mushrooms', 'green peppers', 'extra cheese')
不管收到的是一个值还是三个值,这个函数都能妥善地处理:
制作披萨的所有配料:
-pepperoni
制作披萨的所有配料:
-mushrooms
-green peppers
-extra cheese
结合使用位置实参和任意数量实参
如果要让函数接受不同类型的实参,必须在函数定义中将接纳任意数量实参的形参放在最后。Python
先匹配位置实参和关键字实参,再将余下的实参都收集到最后一个形参中。
>>> def make_pizza(size, *toppings):
"""概述要制作的比萨"""
print("\n制作一个 " + str(size) +
"寸披萨所需配料:")
for topping in toppings:
print("- " + topping)
先打印尺寸,在打印配料:
制作一个 16寸披萨所需配料:
- pepperoni
制作一个 12寸披萨所需配料:
- mushrooms
- green peppers
- extra cheese
使用任意数量的关键字实参
有时候,需要接受任意数量的实参,但预先不知道传递给函数的会是什么样的信息。在这种情况下,可将函数编写成能够接受任意数量的键—值对——调用语句提供了多少就接受多少。只要坚持一个原则,无论用户输入的实参有多少信息,采用遍历的方式将其逐步返回,然后打印就可以实现无论用户输入什么信息就返回。
>>> def build_profile(first, last, **user_info):
"""创建一个字典,其中包含我们知道的有关用户的一切"""
profile = {}
profile['first_name'] = first
profile['last_name'] = last
for key, value in user_info.items():
profile[key] = value
return profile
>>> user_profile = build_profile('albert', 'einstein', location='princeton',field='physics')
>>> print(user_profile)
{'first_name': 'albert', 'last_name': 'einstein', 'location': 'princeton', 'field': 'physics'}
将函数存储在模块中
函数的优点之一是,使用它们可将代码块与主程序分离。通过给函数指定描述性名称,可让 主程序容易理解得多。你还可以更进一步,将函数存储在被称为模块的独立文件中,再将模块导入到主程序中。import
语句允许在当前运行的程序文件中使用模块中的代码。
导入整个模块
要让函数是可导入的,得先创建模块。模块是扩展名为.py
的文件,包含要导入到程序中的代码。创建模块代码示例:
def make_pizza(size, *toppings):
"""概述要制作的比萨"""
print("\nMaking a " + str(size) + "-inch pizza with the following toppings:")
for topping in toppings:
print("- " + topping)
保存为make_pizza.py
的文件,然后创建一个新的文件make.py
。代码如下:
import make_pizza
make_pizza.make_pizza(16, 'pepperoni')
运行后结果如下:
➜ make.py
Making a 16-inch pizza with the following toppings:
- pepperoni
导入模块的某些函数
既然可以导入整个模块,说明是能完全读取整个模块的信息,同理,可以推出,我们导入文件的时候是不是可以将某些函数导入进入使用呢?具体的语法如下:
导入某一个函数:
from module_name import function_name
导入某些函数,也就是多个函数:
from module_name import function_0, function_1, function_2
具体的使用方法同理,相当于该函数就可以被调用,和函数调用一致,没有什么区别。即:
from pizz import make_pizz
make_pizz(12,'demo_pizz')
使用as
给函数指定别名
某些业务的需求,函数名可能有特别长,但是在新的模块文件中,我们不需要这样的函数名,一来影响代码的美观;二来对开发人员不太友好,于是采用关键字as
可以给函数取一个在新的模块中的别名。具体的语法如下:
from module_name import function_name as fun_name
在这里可以看到fun_name
就是为function_name
起的别名,在调用的时候就可以直接采用fun_name
进行调用。具体调用方法如下:
from pizz import make_install_pizz_div as mpip
mpip(14,'pizz_name')
具体的调用和实际导入的函数没有什么区别,同样的使用。但是为了提高代码的可读性,建议最好将别名取的有意义。
使用as
给模块指定别名
由使用as
给函数指定别名可以推出,同样可以为模块取一个更有意义或者更适合自己的别名。在日常的Python
开发中,常用的库或模块有很多,我们同样可以进行别名的方式来实现。具体语法如下:
import module_name as mn
使用方式不再阐述,和没有指定别名的方式是一样的。
导入模块中的所有函数
在日常开发中*
通常是通配符的意思,所以我们要实现一个导入模块的所有函数可以用*
来实现。具体语法如下:
from module_name import *
调用对应函数的方法和上面类似,不做过多的阐述。
函数编写指南
原文内容
编写函数时,需要牢记几个细节。应给函数指定描述性名称,且只在其中使用小写字母和下划线。描述性名称可帮助你和别人明白代码想要做什么。给模块命名时也应遵循上述约定。
每个函数都应包含简要地阐述其功能的注释,该注释应紧跟在函数定义后面,并采用文档字符串格式。文档良好的函数让其他程序员只需阅读文档字符串中的描述就能够使用它:他们完全可以相信代码如描述的那样运行;只要知道函数的名称、需要的实参以及返回值的类型,就能在自己的程序中使用它。
给形参指定默认值时,等号两边不要有空格。PEP 8建议代码行的长度不要超过79字符,这样 只要编辑器窗口适中,就能看到整行代码。如果形参很多,导致函数定义的长度超过了79字符,可在函数定义中输入左括号后按回车键,并在下一行按两次Tab键,从而将形参列表和只缩进一层的函数体区分开来。大多数编辑器都会自动对齐后续参数列表行,使其缩进程度与你给第一个参数列表行指定的 缩进程度相同:
如果程序或模块包含多个函数,可使用两个空行将相邻的函数分开,这样将更容易知道前一个函数在什么地方结束,下一个函数从什么地方开始。所有的import语句都应放在文件开头,唯一例外的情形是,在文件开头使用了注释来描述整个程序。