def 函数名():函数体
之后调用函数引用函数名,括号中加参数信息(没有则空着)。
def greet():
print("hello")
greet()
加入信息传递。这里括号中加入了参数name,在调用函数的时候赋予name的值参与函数的调用。
def greet(name):
print("hello " + name)
greet('alice')
#显示hello alice
在上述代码中,name是一个形参,他没有被赋值,需要调用函数的时候改变他的值来得到具体的数据。而调用函数中的alice是实参,是调用函数时传递给函数的具体信息。
要求实参顺序与形参相同。下面代码中,宠物类型和宠物名字按顺序一一对应。
def pet(animal_type,pet_name):
print(pet_name + " is a cute " + animal_type)
pet('dog','wangwang')
pet('cat','mimi')
#打印结果
#wangwang is a cute dog
#mimi is a cute cat
函数是非常便捷的,我们定义了特定功能的函数之后,就可以多次调用。只需要给出函数名和要传递的实参信息,就可以实现需要的功能。
关键字实参是传递形参名-实参值对,简单来说就是位置实参虽然只需要给出要传递的实参信息,但是如果顺序出错就会造成语义错误,而计算机通常不会发现,拿上面代码举例,如果cat和mimi的位置反了,打印的结果就是猫是一只可爱的咪咪了,那真是闹了笑话。为了减少这样的错误,我们在传递信息的时候先写出这个实参对应的哪个形参,也就是传递形参名-实参对。还是刚刚的代码:
def pet(animal_type,pet_name):
print(pet_name + " is a cute " + animal_type)
pet(animal_type ='dog',pet_name ='wangwang')
pet(animal_type ='cat',pet_name ='mimi')
当然也可以用默认值的方式,即在部分形参中直接给出相对应实参的数据,这时在调用的时候不给出实参,这个参数的值自动显示默认值,若想重新修改,就按原样全都传递新的实参即可。
下面看一个错误代码:
def pet(animal_type='dog',pet_name):
print(pet_name + " is a cute " + animal_type)
pet('wangwang')
pet(pet_name='wangwang')
pet('cat','mimi')
pet(animal_type ='cat',pet_name ='mimi')
他的报错如下
SyntaxError: parameter without a default follows parameter with a default
意思是将没有默认值的参数在定义时放在了有默认值的参数的后面,这是错的。这里注意,如果要给形参设置默认值,要把这个形参放在最后。对此我们修改代码,把animal_type默认值放在最后,修改后的代码如下:
def pet(pet_name,animal_type='dog'):
print(pet_name + " is a cute " + animal_type)
#直接给出pet_name默认动物为狗
pet('wangwang')
#同理加上关键字也是一样
pet(pet_name='wangwang')
#若想修改默认的值需要给出完整的实参
pet('mimi','cat')
pet(animal_type ='cat',pet_name ='mimi')
运行结果如下:
wangwang is a cute dog
wangwang is a cute dog
mimi is a cute cat
mimi is a cute cat
而如果我们既没有默认值又没有给出实参,一般会报错
TypeError: pet() missing 2 required positional arguments: 'pet_name' and 'animal_type'
很多时候我们需要函数返回我们一些值,比如加法函数我们需要其返回一个结果。
我觉得这个代码需要注意的是:如果我们要返回一个变量,我们需要先定义一个变量名去赋予我们需要他实现的功能之后的结果(代码中为message)。同时返回了的值通常不会直接显示,我们需要在主函数中体现出来,还需要我们在设置一个变量去囊括我们调用的函数和他的实参,这样也方便后面的打印(代码中为answer)
def pet(pet_name,animal_type):
message = animal_type + pet_name
return message
answer = pet('wangwang','dog')
print(answer)
#结果就是dogwangwang
当然,返回不仅可以返回一个值,还可以返回列表、字典等比较复杂的数据结构。
def pet(pet_name,animal_type):
message = {'type':animal_type,'pet':pet_name}
return message
answer = pet('wangwang','dog')
print(answer)
运行结果
{'type': 'dog', 'pet': 'wangwang'}
如果不确定有几个参数,可以列出最多占位,然后字典里加入一定存在的,后用if语句,如果存在则加入字典之中。如此修改上述代码。主要是加入了age这个变量并引入了if语句。
def pet(pet_name,animal_type,age=''):
message = {'type':animal_type,'pet':pet_name}
if age:
message['age']=age
return message
answer = pet('wangwang','dog',age=7)
print(answer)
运行结果为
{'type': 'dog', 'pet': 'wangwang', 'age': 7}
while循环同理也可以加入到函数的应用中。
列表传递给函数之后,函数就能直接访问其内容,这能极大地提高效率。
比如我们要建立一个函数,需要对用户给定的列表里的所有人进行问候。
#定义一个给输入列表所有用户打招呼的函数
def greet(names):
for name in names:
print("hello " + name)
#给出所有用户的列表
usersnames = ['Alice','Bob','Mike']
#调用函数
greet(usersnames)
#结果为分别对每个用户说hello
我们再来看一个程序,他需要将一个列表中的内容依次进行操作,然后操作过后进入一个新的列表。
def print_models(unprinted_designs,completed_models):
while unprinted_designs:
current_design = unprinted_designs.pop()
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 = ['ipone 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: ipone case
The following models have been printed:
dodecahedron
robot pendant
ipone case
'''
值得注意的是,这个时候如果我们要打印这两个列表。unprinted_designs列表是空的,而completed_models列表是刚开始我们定义的unprinted_designs列表的倒置列表。这里通过运算的转移实现了列表的倒置。
如果我们不希望让初始列表清零,我们可以先复制初始列表,然后用复制之后的列表作为我们参与程序运行的列表。复制列表忘记的去看前两天发的列表篇噢,这里简单描述为切片表示法:function_name(list_name[:]),运用到上面这个打印代码就是修改调用print_models()函数那一行为:
print_models(unprinted_designs[:],completed_models)
为了更直观的观察,我还加入了操作之后查看两个列表的代码,保留原列表修改之后的代码运行结果如下:
'''
Printing model: dodecahedron
Printing model: robot pendant
Printing model: ipone case
The following models have been printed:
dodecahedron
robot pendant
ipone case
['ipone case', 'robot pendant', 'dodecahedron']unprinted_designs列表
['dodecahedron', 'robot pendant', 'ipone case']completed_models列表
'''
至此真正实现倒置 。
有的时候我们并不知道函数需要接受多少个实参,所以我们用形参*toppings来代替一系列形参。*toppings的意思为创建一个空元组,将所有收到的值都封装到这个空元组中。无论*toppings接收到几个实参都加入到元组中(一个值也是如此)。
def pizza(*toppings):
print("\nwe need")
for topping in toppings:
print('- ' + topping)
pizza('mushrooms')
pizza('mushrooms','potatos','tomatos')
上述代码描述了做pizza我们需要什么,这个答案是未知的,需要的东西的数量可能是根据用户而定的,这个时候使用*toppings就很好的解决了这个情况,运行结果如下:
we need
- mushrooms
we need
- mushrooms
- potatos
- tomatos
当然,*toppings也可以混合使用。拿刚刚的代码说,加入我们还需要得到一个pizza的尺寸信息,即我们要让函数接受不同类型的实参,必须在函数定义中将接纳任意数量实参的形参放在最后。
这个是不是和文章前面位置实参中提到的默认值很像,所以这两类特殊情况在和其他形参一块定义的时候,一定是普通在前,特殊在后。例如:
def pizza(size,*toppings):
如果我们不确定数量的信息不是一串列表元素,而是一些不知道类型的信息,这时候我们可以把他们转换成键值对。就需要我们建立一个空字典,囊括所有我们根据不同情况输入的不同数据。
建立一个空字典需要**。
这是一个建立用户简介的代码,我们有已经可以直接配对的形参实参name,也有不确定信息的**info用户信息。代码的主要思路已经在注释中体现。
#定义一个函数,用来建立用户简介
def profile(name,**info):
#简介包含姓名,和用户信息(用户信息暂时未知,用**创建一个空字典)
pro = {}
#将空字典之前的信息以键值对的形式加入到字典中
pro['name'] = name
#遍历输入信息,加入字典中
for k,v in info.items():
pro[k] = v
return pro
user_profile = profile('Alice',location = 'anhui',field = 'physics')
print(user_profile)
运行结果如下:
{'name': 'Alice', 'location': 'anhui', 'field': 'physics'}
函数的主要优点之一就是与主程序分离,或许我们可以直接将其存储在称为模块的独立文件中,需要调用的时候再将模块导入在主程序中。
import语句允许在当前运行的程序文件中使用模块中的代码。
先创建模块,模块是扩展名为.py的文件,包含要导入到程序中的代码。
例如我们要编写一个制作披萨的代码(参考建立一个空元组中的代码,目录跳转一下~),我们的主程序是给出所需要的材料,函数是将所有材料以we need 的形式打印出来。
我们可以先将函数代码设置为pizza.py模块(其中只有def函数下的相关语句)。在主程序make_pizza中我们加入import pizza 的语句(表示允许pizza.py模块导入)然后调用函数
def make_pizza(*toppings):
print("\nwe need")
for topping in toppings:
print('- ' + topping)
以上命名为pizza.py模块
————————————————————————————————
import pizza
#允许导入
pizza.make_pizza('mushrooms')
pizza.make_pizza('mushrooms','potatos','tomatos')
#调用函数前要加上模块名,这里是pizza.
下面为making_pizza.py,是主程序,其中调用了pizza.py中的函数
所以只要使用import语句导入了名为module_name的整个模块,就可以用下面的语法来使用其中任何一个函数:
module_name.function_name()
from module_name import function_name
或者from module_name import function_0,function_1
一般用于要导入的函数名和程序现有名称冲突或者函数名字太长,这个时候我们可以指定一个别名。语法如下:
from module_name import function_name as fn(别名)
返回到模块刚开始pizza的例子,我们的语句为from pizza import make_pizza as mp。
同理,语法结构为import module_name as m(别名)。
需要用到*运算符可让python导入模块中的所有函数。
from module_name import*
这个星号是将模块pizza中的每个函数都复制到程序文件中,因为导入了全部,调用时不需要使用句点表示法,可以直接用名称来调用函数。
然而一般在非自己编写的大型模块的情况下我们不建议使用,避免名称相同等情况产生覆盖等其他不是我们想要的结果。
我们建议:只导入需要使用的函数或者导入整个模块然后使用句点表示法。
函数编写当然还有一些小指南。
例如所有涉及到的名称尽量都要见名知意,上述各种代码我们能感受到我们定义了太多的变量名,这样能帮助我们更好的理解代码。
最好在每个函数后面注释上这个函数是干什么的、需要哪些实参以及返回值的类型,方便阅读和调用。这里很多注释我并没有严格按照规范去表示而是在文字中进行了更多的阐述,希望大家在后续编写的时候多注意。
还有约定是要求默认值和关键字的指定时,等号两边不要空格。(这个我是学到这里才知道,上面的代码大多都是我从pycharm上自己敲完粘过来的,少量自己直接敲的,粘过来的运行应该没有问题,但是没有太注意这个情况,后续编写的时候可以多注意)
包含多个函数可以用两个空行分开,更易懂。
import语句都在文件开头。
......
这是我目前写过最长的一篇博客,每一个字每一行代码都是我一点一点敲出来的,这两天我一直在想要不就这么多发了吧或者想着随便写写结尾把函数过掉。事实上我还是一边摸鱼一边学习整理了所有函数相关的知识,在此期间我也敲了一些代码,自己先实操过了一遍,把一些可能出现的错误、可能难以理解的地方都在博客中标记了出来。我猜可能没有人会在刷到的时候就很认真的看完,但是之后这篇博客如果对初学python的人更好地捋清了函数,成为掌握python基本知识点和真正编写程序之间的一个桥梁,我想这会好酷。希望所有需要用到这些知识点开这篇博客的人都能仔仔细细的读完它(包括之后要复习的我hhhh)。(偷偷蛐蛐我写论文都没敲过这么多,希望他能更有用一点祈祷)
注:内容参考《Python编程 从入门到实践》