函数创建与调用
1). 定义函数:
def 函数名(参数1, 参数2…):
函数执行的内容
2). 定义函数时指定参数和返回值的类型
def mymax(num1: int, num2: int) -> int:
代表num1需要传入整形, num2需要传入整形, 返回值必须是整形。
3). 函数的帮助文档: 三引号
4). 函数调用格式: 函数名([形参值])
举例:找最大值
#一:创建函数
def mymax(num1:int,num2:int)->int:
return num1 if num1>num2 else num2
#二:调用函数
max_num=mymax(1,2)
print(max_num)
举例:理解函数内部调用函数
打印 三行***********
def print1line():
print('*'*30)
def printnumline(num:int):
for i in range(num):
print1line()
#调用
printnumline(3)
举例: 理解返回值
函数内部的print是否打印? 在创建函数时不会执行函数内部的代码,调用才会执行函数内部的代码。
用户登录系统:
def login(name:str,passwd:str)->bool:
if name=='root' and passwd=='redhat':
print('login ok')
return True
else:
print('wrong')
return False
result=login('root','redhat')
print(result)
执行结果:
login ok
True
举例:理解实参与形参
求三个数的和与平均值:
def sum3num(s1:int,s2:int,s3:int)->int:
if isinstance(s1,int) and isinstance(s2,int) and isinstance(s3,int) :#判断传入的实参类型是否正确
return s1+s2+s3
else:
return None
def average3num(num1:int,num2:int,num3:int)->float:#将3,4,5先传给num1,num2,num3,此时num1,num2,num3,为形参
result1=sum3num(num1,num2,num3) #将num1=3,num2=4,num3=5(此时num1,num2,num3,为实参),再传给s1,s2,s3(形参)
result2=result1/3
return result2
a=average3num(3,4,5) #3,4,5为实参
print(a)
执行结果:
4.0
举例:理解局部变量与全局变量
存钱小例子:
all_money=100 #在函数外部定义的变量为全局变量,且数值类型为不可变类型,因此在函数内部使用需要声明:global all_money
operator=[] #全局变量operator且为不可变数据类型,因此无需在函数内部声明
def save_money(money): #money为局部变量,函数内部定义,函数内部作用完会被释放掉
global all_money
print('存之前:',all_money,'操作为:',operator)
all_money+=money
operator.append('存钱')
print('存之后:',all_money,'操作为:',operator)
print('打印函数内部的局部变量:',locals())#打印函数内部的局部变量,locals()当前局部范围内所有变量组成的“变量字典”。
def view_money():
print('所有钱为:',all_money)
save_money(100)
view_money()
print(globals().keys()) #打印全局变量全局范围内所有变量组成的“变量字典”。globals()全局范围内所有变量组成的“变量字典”。
执行结果:
存之前: 100 操作为: []
存之后: 200 操作为: ['存钱']
打印函数内部的局部变量: {'money': 100}
所有钱为: 200
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'all_money', 'operator', 'save_money', 'view_money'])
举例: 理解默认参数:无需写入的参数。
求次方,默认求2次方:
def mypow(x,y=2,z=None): #y、z为默认参数,默认求2次方,如果输入x,y的值,就求x的y次方
return x**y
print(mypow(2))
print(mypow(3,2))
执行结果:
4
9
连接数据库:
def connect_mysql(user,passwd,host='localhost',port='3306',charset='utf-8'):
print('connect myaql.....',user,passwd,host,port,charset)
if __name__ == '__main__':
connect_mysql('scq','redhat')
connect_mysql('scq','redhat',host='1.1.1.1')
执行结果:
connect myaql..... scq redhat localhost 3306 utf-8
connect myaql..... scq redhat 1.1.1.1 3306 utf-8
举例:理解可变数据类型不能作为默认参数:例如列表、字典。
打印[end]:
def add_end(num=[]):
num.append('end')
return num
print(add_end())#['end']
print(add_end())#['end', 'end']
print(add_end())#['end', 'end', 'end']
#不断向num列表添加end,会打印出三个end,但题目只需要一个
执行结果:
['end']
['end', 'end']
['end', 'end', 'end']
举例:理解可变参数*args
:可以传入多个参数给形参,传入参数的个数时可变的,传可变参数时,将参数组成元组赋给args
形参分为:必传参数、默认参数、可变参数
#求a2+b2+c2+....:
result=0
def square_sum(*args):
global result
for i in args:
result+=(i**2) #求平方再累加
return result
print(square_sum(1,2,3))
执行结果:
14
举例: 理解可变参数参数解包。如果实参是多个参数组成的列表,那么需要把列表中的参数全部取出,实参为*列表名
。
#解包理解:
li=[1,2,3]
print(*li) #取出li中的值
执行结果:
1 2 3
#求100以内所有计数平方和:
result=0
def square_sum(*args):
global result
for i in args:
result+=(i**2) #求平方再累加
return result
nums=range(1,100,2)
print(square_sum(*nums)) #将可变参数nums解包,再传给函数square_sum
执行结果:
166664
举例:理解关键字参数**字典名(**kwargs)
,传入key-value对。允许传入 0 个或任意个含参数名的参数,在函数内部自动组装为一个 dict;
def record_student_info(name,age,**kwargs):
print(name,age,kwargs)
record_student_info('scq','18',hobby='piano',size='M')
record_student_info('root','10')#关键字参数不输入时返回空字典
执行结果:
scq 18 {'hobby': 'piano', 'size': 'M'}
root 10 {}
举例:理解关键字参数解包:**字典名
nums=dict(hobby='piano',size='M',member='100')
record_student_info(’scq‘,'22',**nums) #将关键字餐室:字典nums 解包,再传给函数record_student_info
执行结果:
scq 22 {'hobby': 'piano', 'size': 'M', 'member': '100'}
参数总结:
注意:参数定义的顺序必须是:必选参数、 默认参数、可变参数和关键字参数。
匿名函数
举例: 理解匿名函数:匿名函数指一类无须定义标识符的函数或子程序。Python用lambda语法定义匿名函数,只需用表达式而无需申明。(省略了用def声明函数的标准步骤)
lambda函数能接收任何数量的参数但只能返回一个表达式的值。
#求最大值
mymax= lambda num1,num2:num1 if num1>num2 else num2 # 匿名函数格式:lambda形参:返回值
print(mymax(12,13))
执行结果:
13
#求次方
mypow=lambda x,y=2:x**y
print(mypow(1))
print(mypow(3,2))
执行结果:
1
9
举例:理解匿名函数当作形参传入实参
def fun(num1,num2,operator_fun=pow):#默认参数operator_fun=pow将函数pow当作变量赋值给operator_fun,让operator_fun求次方
return operator_fun(num1,num2)
print(fun(2,3))#求2的3次方,默认为求次方
print(fun(2,3,lambda x,y:x+y))#返回5,operator_fun被求和函数赋值,因此求两数之和
执行结果:
8
5
举例:理解匿名函数作为内置函数的参数
#打印商品信息
goods=[
('python',200,20),
('java',100,30),
('c',50,40)
]
from prettytable import PrettyTable
def show(goods):
table=PrettyTable(field_names=['name','count','price'])
for good in goods:
table.add_row(good)
print(table)
print('按照数量排序'.center(30,'*'))
goods.sort(key=lambda x:x[1]) #设置key之后,sort将列表goods中的每一个元素传入x中寻找x中索引为1的值:200,100,50传给key,sort根据key按照从小到大排序,最后返回整体列表元素排序结果
show(goods)
print('按照价格排序'.center(30,'*'))
goods.sort(key=lambda x:x[2])
show(goods)
执行结果:
************按照数量排序************
+--------+-------+-------+
| name | count | price |
+--------+-------+-------+
| c | 50 | 40 |
| java | 100 | 30 |
| python | 200 | 20 |
+--------+-------+-------+
************按照价格排序************
+--------+-------+-------+
| name | count | price |
+--------+-------+-------+
| python | 200 | 20 |
| java | 100 | 30 |
| c | 50 | 40 |
+--------+-------+-------+
#给定一个整形数组, 将数组中所有的0移动到末尾, 非0项保持不变;输入: 数组的记录;0 7 0 2输出: 调整后数组的内容; 7 2 0 0
li=[0,7,0,2]
li.sort(key=lambda x:1 if x==0 else 0)
print(li)
执行结果:
[7,2,0,0]
# sort实现原理:
# 先取出列表中的元素: 0 7 0 2
# / / / /
# 1 if x==0 else 0 赋值: 1 0 1 0
# 将 1 0 1 0由小到大排列,再输出对应的元素: [7,2,0,0]
#有一个整数列表(10个元素), 要求调整元素顺序,把所有的奇数放在前面,偶数放在后面,
li=[0,7,1,2,8,6,9]
li.sort(key=lambda x:1 if x%2==0 else 0)
print(li)
执行结果:
[7, 1, 9, 0, 2, 8, 6]
递归函数
举例:理解 一个函数在内部调用自己本身,这个函数就是递归函数
求阶乘:
def factorial(num):
# 递归求阶乘
# 递归退出条件:num<=1
# 递归规则: num!=num*(num-1)!
# :param num:
# :return:
if num >1:
result=num*factorial(num-1)
return result
else:
return 1
if __name__ == '__main__':
print(factorial(3)) #求3的阶乘
执行结果:
6
递归原理如图:
#斐波那契数列(Fibonacci sequence),又称黄金分割数列,指的是这样一个数列:1、1、 2、3、5、8、13、21、34...
求数列第num个的值:
def fib(num):
# 退出条件:num=1或2
# 递归规则:f(n)=f(n-1)+f(n-2)
# :param num:
# 弊端:此方法会重复计算值,因此计算速度很慢
if num>2:
result=fib(num-1)+fib(num-2)
return result
else:
return 1
if __name__ == '__main__':
print(fib(5)) #数列第五个数的值
print(fib(20)) #数列第20位的值
执行结果:
5
6765
汉诺塔递归函数 3个盘子
movecount=0
def hanoi(n=3,start='A',cache='B',target='C'):
'''
退出条件; n=1 盘个数为1
规则:类似于把大象从冰箱拿出来(1:打开冰箱门。2:取出大象.3关闭冰箱门)
分三步:hanoi(n-1,start,target,cache) #最底层盘子为大象,先将上层所有盘子放到缓冲塔cache中(打开冰箱门)
hanoi(1,start,cache,target) #将最底层盘子放到目标塔 (取出大象)
hanoi(n-1,cache,start,target) #将缓冲塔的所有盘子放到目标塔(关闭冰箱门)
:param n: 盘子个数
:param start: 初始塔
:param cache: 缓冲塔
:param target: 目标塔
:return:
'''
if n == 1:
print('从%s移动到%s'%(start,target))
global movecount
movecount+=1#n=1时才会移动盘子,此时才会记录次数加1
else:
hanoi(n-1,start,target,cache) #n!=1时,将默认参数start,cache,target=A、B、C作为实参传给此处的形参start,target,cache,其中start为初始塔 target实参传给函数形参cache,作为缓冲塔,实参cache传给形参target,作为目标塔
hanoi(1,start,cache,target)#此函数的实参为上一级函数形参传入值
hanoi(n-1,cache,start,target)
print(hanoi(4))
print(movecount)
执行结果:
从A移动到B
从A移动到C
从B移动到C
从A移动到B
从C移动到A
从C移动到B
从A移动到B
从A移动到C
从B移动到C
从B移动到A
从C移动到A
从B移动到C
从A移动到B
从A移动到C
从B移动到C
15