1 函数的创建于调用
1.1 创建一个函数
创建函数也称为定义函数,定义函数的格式如下:
def functionname([parameterlist]):
['''comments''']
[functionbody]
参数说明:
functionname:函数名称,在调用函数时使用。
parameterlist:可选参数,用于指定向函数中传递的参数。如果有多个参数,各参数间使用逗号","分隔。如果不指定,则表示该函数没有参数,在调用时也不用指定参数。
“comments”:可选参数,表示为函数指定注释,注释的内容通常是说明该函数的功能、要传递的参数的作用等。
functionbody:可选参数,用于指定函数体,即该函数被调用后,要执行的功能代码。如果函数有返回值,可以使用return语句返回。
如果像定义一个什么也不做的空函数,可以使用pass语句作为占位符。
def fn(*nums):
'''
函数的作用: 计算任意数值的总和
函数的参数: *nums 会接受所有传进来的值,保存到一个元组中(装包)
'''
print(nums,type(nums))
result = 0 # 定义一个变量,用来保存总和
for n in nums:
result += n
return result
help(fn)
在定义函数时,如果指定了“comments”参数,那么在调用函数时,输入help(函数名)可以得到注释信息。
注意:
- 即使函数没有参数,也必须保留一对空的“()”,否则会报SyntaxError: invalid syntax的错误
- 函数体“functionbody”和注释“"comments"”相对于def关键字必须保持一定的缩进
1.2 调用函数
调用函数就是执行函数。定义了函数之后,就相当于有了一个具有某些功能的代码,想要让这些代码能够执行,需要调用它。调用函数的基本语法格式:
Functionname([parmnetersvalue])
参数说明:
functionname:函数名称,要调用的函数名称必须是已经创建好的。
parmnetersvalue:可选参数,用于指定各个参数的值。如果需要传递多个参数值,则各参数值间使用逗号“,”分隔。如果该函数没有参数,直接写一对小括号即可。
def fn(*nums):
'''
函数的作用: 计算任意数值的总和
函数的参数: *nums 会接受所有传进来的值,保存到一个元组中(装包)
'''
print(nums,type(nums))
result = 0 # 定义一个变量,用来保存总和
for n in nums:
result += n
return result
fn(1,2,3,4)
运行结果:
1.3任务一: 泸州老窖销售人员工资计算
【任务描述】
泸州老窖公司销售人员工资由基础工资+工龄工资+业绩提成构成,基础工资为1000,工龄工资为100*工龄,创建一个函数,计算每个员工的月工资。
【任务分析】
按照任务描述,已知员工的基础工资、员工的工龄和业绩提成,可以写一个函数,一员工工龄和业绩提成作为两个输入参数构建。
【实现步骤】
1.创建模块,并且命名
2.编写工资函数
3.调试函数,使之可以正确调用
def salary(work_age, performance):
basic = 1000
work_age_salary = 100 * work_age
tatal_salary = basic + work_age_salary + performance
return tatal_salary
print('你的工资是:',salary(19,5000)) # 调用函数
#运行结果
#你的工资是: 7900
注意:
- 函数定义好以后,函数体里的代码并不会执行,如果想要执行函数体里的内容,需要手动的调用函数。
- 每次调用函数时,函数都会从头开始执行,当这个函数中的代码执行完毕后,意味着调用结束了。
- 当然了如果函数中执行到了return也会结束函数。
2 参数传递
2.1 了解形式参数和实际参数
在使用函数时,经常会用到形式参数和实际参数。
形式参数:在定义函数时,函数名后面括号中的参数为“形式参数”。
实际参数:在调用一个函数时,函数名后面括号中的参数为“实际参数”,也就是将函数的调用者提供给函数的参数称为实际参数。
当实际参数为不可变对象时,进行值传递;
当实际参数为可变对象时,进行的是引用传递。
值传递和引用传递的基本区别就是进行值传递后改变形式参数的值,实际参数的值不变;而进行引用传递后,改变形式参数的值,实际参数的值也同一改变。
a = [1, 2, 3, 4]
b = 1
# 值传递
def changer_list(list1):
list1[0] += 1
return list1
print(changer_list(a))
print(a) # 值传递a改变
# 参数传递
def changer_interger(num):
num += 1
return num
print(changer_interger(b))
print(b) # 参数传递b不变
运行结果:
从上面的运行结果可以看出,在进行值传递时,改变形式参数的值后,实际参数的值不改变;在进行引用传递时,改变形式参数的值后,实际参数的值也发生改变。
2.2. 位置参数
位置参数也称必备参数,是必须按照正确的顺序传到函数中,即调用时的数量和位置必须和定义时是一样的。
2.2.1.数量必须与定义时一致
运行结果:
从上图所报异常信息可以看出,抛出的异常类型为TypeErro,具体是指“price()”方法缺少一个必要的位置参数z“。
2.2.2.位置必须与定义时一致
在调用函数时,指定的实际参数的位置必须与形式参数的位置一致,否则会产生两种结果。
情况一抛出TypeError异常:
运行结果:
从上面运行结果所报的异常,可以发现报错原因是因为传递的整型数值不能与字符串进行连接操作。
情况二产生的结果与预期不符:
运行结果:
预期运行的结果:
从结果中可以看出,虽然没有抛出异常,但是得到的结果与预期不一致。
2.3 关键字参数
关键字参数是指使用形式参数的名字来确定输入的参数值。通过该方式指定实际参数时,不再需要与形式参数的位置完全一致。只要将参数名写正确即可。
运行结果:
2.4 为参数设置默认值
调用函数时,如果没有指定某个参数将抛出异常,为了解决这个问题,可以为参数设置默认值,即在定义函数时,直接指定形式参数的默认值。定义带有默认值参数的函数的语法格式:
def functionname(...,[parameter1=defaultvalue1]):
[functionbody]
参数说明:
functionname:函数名称,在调用函数时使用。
parameter1=defaultvalue1:可选参数,用于指定向函数中传递的参数,并且为该参数设置默认值为defaultvalue1。
functionbody:可选参数,用于指定函数体,即该函数被调用后,要执行的功能代码。
运行结果:
注意:在定义函数时,指定默认的形式参数必须在所有参数的最后,否则将产生语法错误。
多学两招:
在python中,可以使用“函数名.__default__”查看函数的默认值参数的当前值,其结果是一个元组。
在使用可变对象作为函数参数的默认值时,多次调用可能会导致意料之外的情况。
连续调用两次
def demo(obj = []):
print('obj的值:',obj)
obj.append(1)
#连续调用两次demo()函数,并且都不指定实际参数
demo()
demo()
运行结果:
解决办法,使用None作为可变对象的默认值:
def demo(obj = None):
if obj == None:
obj = []
print('obj的值:',obj)
obj.append(1)
#连续调用两次demo()函数,并且都不指定实际参数
demo()
demo()
运行结果:
2.5 任务二:酒价格计算
【任务描述】
商店出售三种酒,国窖1573、茅台、泸州老窖。其中国窖1573每瓶1000元,茅台每瓶300元,泸州老窖每瓶200元,每次卖酒都将每种酒的价格乘以酒的瓶数再相加这种计算方法过于繁琐,要求写一个函数,输入各种酒的瓶数,打印出购买人买酒的信息,输出中有购买人的名字
【任务分析】
按照任务描述,已知每种酒的瓶数和价格,在这里可以将酒的价格作为常量,酒的瓶数作为函数的参数传入函数做计算。这里有三种酒和一个人名,需要为函数设置4个参数,输出使用print函数。
laojiao1573 = 1000
maotai = 300
laojiao = 200
def price(person, x, y, z): # person代表购买人;x,y,z分别表示老窖1573,茅台,泸州老窖的瓶数
total = laojiao1573 * x + maotai * y + laojiao * z
print(person, '您购买的酒总价格为:', total)
price('陈先生', 10, 20, 30)
运行结果:
2.6 可变参数
可变参数也称不定义参数,即传入函数中的实际参数可以是任意多个。
定义可变参数时,主要有两种形式:一种是*parameter,另一种是**parameter
2.6.1 *parameter
这种形式表示接收任意多个实际参数并将其放到一个元组中。
例如,定义一个函数,让其可以接收任意多个实际参数
def favorite_wine(*wine):
print('我喜欢吃的有:')
for i in wine:
print(i)
favorite_wine('烤串','炸串','烤肉')
favorite_wine('烤串','炸串')
favorite_wine('烤串')
运行结果:
如果想使用一个已经存在的列表作为函数的可变参数,可以在列表的名称前加“*”。
def favorite_wine(*wine):
print('我喜欢吃的有:')
for i in wine:
print(i)
wine = ['烤串','炸串','烤肉']
favorite_wine(*wine)
运行结果:
2.6.2 任务三:多客户酒价格计算
【任务描述】
商店出售三种酒,国窖1573、茅台、泸州老窖。其中国窖1573每瓶1000元,茅台每瓶300元,泸州老窖每瓶200元,每次卖酒都将每种酒的价格乘以酒的瓶数再相加这种计算方法过于繁琐,如果同时有多个客户购买白酒,要求书写一个函数,输入各位客户的名字以及相应的酒的瓶数,同时打印出各位客户买酒的信息(输出中有客户的名字)。
【任务分析】
按照任务描述,结合不定长参数,将各位客户的信息输入到一个列表中,相当于一个嵌套列表,一个大列表里有许多小列表,每个小列表代表一个客户信息以此来构建函数。
laojiao1573 = 1000
maotai = 300
laojiao = 200
def price_upgrade( *customer_imfo_list):
'''
输入的数据为一个列表如[("李先生",10,20,30),("王小姐",2,2,2),("陈总",1,2,3)]
每个列表中可以有多个tuple,tuple中第一个位置代表客户名字,其他三个数字分别代表购买
老窖1537,茅台,泸州老窖的数量,输出每个客户买酒的总价格
'''
for i in customer_imfo_list:
for j in i:
print("=" * 10 + j[0] + "=" * 10)
total = laojiao1573 * j[1] + maotai * j[2] + laojiao * j[3]
print(j[0],'您买酒的总价格为:',total)
customers_info = [("李先生",10,20,30),("王小姐",2,2,2),("陈总",1,2,3)]
price_upgrade(customers_info)
运行结果:
2.6.3 **parameter
**parameter表示接收任意多个类似关键字参数一样显示赋值的实际参数,并将其放到一个字典中。
例如,定义一个函数,让其可以接收任意多个显式赋值的实际参数
def printinfo(**pram):
print()
for key,value in pram.items():
print("["+key+"]喜欢喝" + value)
#调用两次printinfo()函数
printinfo(杜甫="茅台",李白="啤酒")
printinfo(小李="烤串",小陈="炸鸡",小美="果汁")
运行结果:
如果想要使用一个已经存在的字典作为函数的可变参数,可以在字典的名称前加”**“。
def printinfo(**pram):
print()
for key,value in pram.items():
print("["+key+"]喜欢喝" + value)
dict1 = {"小李":"烤串","小陈":"炸鸡","小美":"果汁"}
printinfo(**dict1)
运行结果:
3 返回值
所谓“返回值”,就是指程序中函数完成一件事情后,最后给调用者的结果
使用返回值的前提需求就是函数调用者想要在函数外使用计算结果
如果返回一个值,那么返回的结果类型可以为任意类型。
如果返回多个值,那么结果中的是一个元组
当函数中没有return语句时,或者省略了return语句的参数时,将返回None,即返回空值。
3.1 带有返回指的函数
#在函数中把结果返回给调用者,需要在函数中使用return
def add2num(a,b):
c = a+b
return c # return 后可以写变量名
#或者
def add1num(a,b):
return a+b # return 后可以写计算表达式
3.2 报存函数的返回值
#保存函数的返回值
#定义函数
def addnum(a,b):
return a + b
#调用函数,顺便保存函数的返回值
result = addnum(10,88)
#因为result已经保持了addnum的返回值,所以接下来就可以直接使用了
print(result) # 98
3.3 任务四:多客户酒价格计算
【任务描述】
场景模拟:泸州某酒厂开厂大促销,优惠如下:
满500元享受9折优惠
满1000元享受8折优惠
满2000元享受7折优惠
满3000元享受6折优惠
根据以上酒厂促销活动,计算优惠后的实付金额。
【任务分析】
按照任务描述,首先需要创建一个名称为checkout.py的文件,然后再该文件中定义一个名称为settle_accounts的函数,该函数包括一个列表类型的参数,用于保存输入的金额,在该函数中计算合计金额和相应的折扣,并将计算结果返回,最后在函数体外通过循环输入多个金额保存到列表中,并且将该列表作为settle_accounts函数的参数调用。
def settle_accounts(money):
'''
功能:计算白酒总价并打折,输出应付金额
money是一个列表,里面包含购买的各种酒的价格
'''
total = sum(money)
if 0<=total<500:
should_pay = total
elif 500<=total<1000:
should_pay = total*0.9
elif 1000<=total<2000:
should_pay = total*0.8
elif 2000<=total<3000:
should_pay = total*0.7
elif 3000<=total:
should_pay = total*0.6
should_pay = '{:.2f}'.format(should_pay) # 保留两位小数
return total,should_pay
#调用函数
print('\n开始计算……')
money_list = []
while True:
input_money = float(input("输入商品金额(输入0表示输入完毕):"))
if int(input_money) == 0:
break
else:
money_list.append(input_money)
money = settle_accounts(money_list)
print('合计金额:',money[0],'实付金额',money[1])
运行结果:
4 变量的作用域
变量的作用域是指程序代码能够访问该变量的区域,如果超出该区域,再访问时就会出现错误。一般会根据变量的有效范围将变量分为全局变量和局部变量。
4.1 局部变量
局部变量是指在函数内部定义并使用的变量,它只在函数内部有效。即函数内部的名字子在函数运行时才会创建,在函数运行之前或者运行完毕之后,所有的名字就都不存在了。所以,如果在函数外部使用函数内部定义的变量,就会出现抛出异常。
例如:定义一个名称为f_demo的函数,在定义一个变量message(称为局部变量),并为其赋值,然后输出该变量,最后在函数体外部再次输出message变量。
def demo():
message = "我喜欢钱,我要挣大钱"
print("局部变量",message)
demo()
print(message)
运行结果
4.2 全局变量
全局变量为能够作用于函数内外的变量。有两种情况:
4.2.1 如果一个变量,在函数外定义,那么不仅在函数外可以访问到,在函数内也可以访问到。在函数体以外定义的变量是全局变量。
message = "我喜欢钱,我要挣大钱"
def demo():
print("函数体内输出全局变量",message)
demo()
print("函数体外输出全局变量",message)
运行结果:
说明:当局部变量与全局变量重名时,对函数体的变量进行赋值后,不影响函数体外的变量。
4.2.2 任务五:一个酒鬼的梦
【任务描述】
一个酒鬼喜欢喝酒,现实中只能和廉价的二锅头配花生,当他开始做梦时,他在梦中可以喝到高级的国窖1573配烤鸭吃,创建函数试着描绘此场景。
【任务分析】
按照任务描述,本次任务涉及到全局变量和局部变量的问题,可以将酒鬼的现实情况用全局变量描绘,放入字符串中,创建函数,可以将函数作为一个梦,调用函数时描绘梦中的场景,从函数体中出来,就像梦行了进入了现实一样。
reality = "喝二锅头配咸菜"
def dream():
elusion = "喝泸州老窖1573配烤鸭"
print("开始做梦……")
print(elusion)
print()
print('梦醒了')
dream()
print('现实是:',reality)
运行结果:
4.2.3 在函数体内定义,并且使用global关键字修饰后,该变量也就变为全局变量。在函数体外可以访问到该变量,并且在函数体内还可以对其进行修改。
例如:定义两个同名的全局变量和局部变量,并输出它们的值。
msg = "这是一个全局变量" # 定义一个全局变量
print('函数体外:',msg)
def demo():
msg = "这是一个局部变量" # 定义一个局部变量
print('函数体内:',msg)
demo()
print('函数体外:',msg)
运行结果:
从上面的运行结果来看,在函数内部定义的变量即使与全局变量重名,也不影响全局变量的值。
如果想要在函数体内部改变全局变量的值,需要在定义局部变量时,使用global关键字修饰。
glb = "这是一个全局变量" # 定义一个全局变量
print('函数体外:',glb)
def change_global():
global glb # global关键字能够用在函数内改变全局变量
glb = "这是一个全局变量,在函数中改变了"
print('函数体内:',glb)
change_global()
print('函数体外:',glb)
运行结果:
注意:尽管python允许全局变量和局部变量重名,但是在开发时,不建议这样使用,因为这样容易让代码混乱,很难分清哪些是全局变量,哪些是局部变量。在定义函数时,指定默认的形式参数必须在所有参数的最后,否则将产生语法错误。
5 匿名函数
匿名函数是指没有名字的函数,应用在需要一个函数,但是又不想费神去命名这个函数的场合。通常情况下,这样的函数只使用一次。在python中,使用lambda表达式创建匿名函数,其语法格式:
result = lambda[arg1[arg2,...,argn]]:expression
参数说明:
result:用于调用lambda表达式。
[arg1[arg2,...,argn]:可选参数,用于指定要传递的参数列表,多个参数间使用逗号","分隔。
expression:必选参数,用于指定一个实现具体功能的表达式。如果有参数,那么在该表达式中将应用这些参数。
注意:使用lambda表达式时,参数可以有多个,用逗号”,”分隔,但是表达式只能有一个,即只能返回一个值。而且也不能出现其他非表达式语句(如for或while)。
例如:定义一个计算圆面积的函数,常规的代码如下:
import math
def circlearea(r):
result = math.pi*r*r # pi为圆周率
return result
r = 10
print('半径为:',r,"的圆的面积为:",circlearea(r))
运行结果:
使用lambda表达式的代码如下:
import math
r = 10
resutl = lambda r:math.pi*r*r # math.pi为圆周率
print('半径为:',r,"的圆的面积为:",resutl(r))
运行结果:
从上面的示例中可以看出,虽然使用lambda表达式比使用自定义函数的代码减少了一些,但是在使用lambda表达式时,需要定义一个变量,用于调用该lambda表达式,否则将输出类似的结果: