1.函数
为什么需要函数?
如果在开发程序时,需要某块代码多次,但是为了提高编写的效率以及代码的重用,所以把具有独立功能的代码块组织为一个小模块,这就是函数.
数学中的函数
深入理解函数: 变量x只能是任意数吗?
变量在本质上就是一个占位符。变量可以用x,也可以用别的符号,比如y,z,k,i,j…,甚至用alpha,beta这样的字母组合也可以。
2.函数创建和调用
函数范例
空函数
定义一个什么事也不做的空函数,可以用 pass 语句;
pass 可以用来作为占位符,还没想好怎么写函数的代码,就可以先放一个 pass ,让代码能运行起来
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190521203236497.png)
函数返回值
所谓“返回值”,就是程序中函数完成一件事情后,最后给调用者的结果.
没有返回值,默认返回None
定义函数的格式
def 函数名(参数1,参数2,...,参数n):
函数体(语句块)
函数名的命名规则要符合python中的命名要求。一般用小写字母和单下划线、数字等组合
匈牙利命名法(sUserName), 驼峰式大小写(userName), 帕斯卡命名法(UserName)
def是定义函数的关键词,这个简写来自英文单词define
函数名后面是圆括号,括号里面,可以有参数列表,也可以没有参数
千万不要忘记了括号后面的冒号
函数体(语句块),相对于def缩进,按照python习惯,缩进四个空格
例:猜数字游戏(函数版)
随机生成1-100内的一个数字,输入猜的次数,然后输入一个数,如果不一样就会提醒太大或太小,在次数用完前匹配例就成功,否则失败。
代码:
import random
#1). 形参-定义函数时里面的参数: 形式参数(可以任意修改名字)
#2). 如果函数没有return, 默认会返回None;
3). 实参-调用函数时指定的值 : 实际存在的参数
def isEuqal(guessNum, gameNum):
"""
判断用户猜测的数字和游戏给定的数字是否相等?
:param guessNum:
:param gameNum:
:return: Bool-是/否
"""
if guessNum > gameNum:
print("太大了")
return False
elif guessNum < gameNum:
print("太小了")
return False
else:
print("恭喜你, 中了100万")
return True
def main():
"""
脚本的主函数
:return:
"""
gameNum = random.randint(1, 100)
num = int(input('请输入猜数字最多次数:'))
for count in range(num):
guessNum = int(input("请开始游戏, 猜测数字(1-100):"))
if isEuqal(guessNum, gameNum):
break
else:
print("游戏结束, 一百万还很遥远")
main()
运行截图:
函数的优势
从理论上说,不用函数,也能够编程,我们在前面已经写了程序,就没有写函数,当然,用python的内建函数姑且不算了。现在之所以使用函数,主要是:
- 降低编程的难度(分而治之的思想)
- 代码重用。避免了重复劳动,提供了工作效率。
3.变量作用域
局部变量
局部变量,就是在函数内部定义的变量
不同的函数,可以定义相同的名字的局部变量,但是各用个的不会产生影响
局部变量的作用,为了临时保存数据需要在函数中定义变量来进行存储。
全局变量
如果一个变量,既能在一个函数中使用,也能在其他的函数中使用,这样的变量就是全局变量。
在函数外边定义的变量叫做全局变量
全局变量能够在所有的函数中进行访问
如果在函数中修改全局变量,那么就需要使用global进行声明,否则出错
如果全局变量的名字和局部变量的名字相同,那么使用的是局部变量的
小技巧: 强龙不压地头蛇(就近原则)
不使用global声明全局变量时不能修改全局变量?
global的本质是声明可以修改全局变量的指向, 即变量可以指向新的数据。
1). 不可变类型的全局变量: 指向的数据不能修改, 不使用global时无法修改全局变量。
2). 可变类型的全局变量: 指向的数据可以修改, 不使用global时可以修改全局变量。
定义全局变量
allMoney = 100
operator = []
def save_money(money):
"""存钱"""
global allMoney
print("存钱前:", allMoney, operator)
allMoney += money
# 为什么operator不需要声明为全局变量?因为它是可变类型的全局变量,不需要global声明
operator.append('存钱操作')
print("存钱后:", allMoney, operator)
def view_money():
"""查询金额"""
#allMoney = 500
operator.append("查询金额操作")
print("查询金额:", allMoney, operator)
if __name__ == '__main__':
save_money(50)
view_money()
4.参数传递
形参与实参
定义时小括号中的参数,用来接收参数用的,称为 “形参”,形参的名字可以随便起
调用时小括号中的参数,用来传递给函数用的,称为 “实参”
参数检查
调用函数时,如果参数个数不对,Python 解释器会自动检查出来,并抛出 TypeError;
如果参数类型不对,Python 解释器就无法帮我们检查。
数据类型检查可以用内置函数 isinstance 实现
告诉解释器, 形参的类型, 和返回值的类型
def add(x: int, y: int) -> int:
# if type(x) == int and type(y) == int:
# iterable可迭代的,
# all是python的内置方法, 如果全为True, 返回True, 有一个为Flase,返回False;
# any是python的内置方法, 如果全为False, 返回False, 有一个为True,返回True;
if all([isinstance(x, int), isinstance(y, int)]):
return x + y
print(add(1, 2))
如果参数类型不对,Python 解释器就无法帮我们检查。(type,isinstance )
print(add('hello', 1))
调用函数时,如果参数个数不对,Python 解释器会自动检查出来,并抛出 TypeError;
print(add('hello'))
isinstance查看/判别数据类型的
print(isinstance('hello', str))
print(isinstance('hello', int))
默认参数
需求: 定义一函数,计算x值的n次方。那如果计算x平方时只需要传入x值时怎么解决?
默认参数可以降低调用函数的难度。
默认参数注意事项:
有多个参数时,变化大放前面,变化小的放后面;
必选参数在前,默认参数在后
默认参数的默认值一定是不可变参数;
def mypow(x: int, y: int = 2) -> int:
"""
求x的y次方
return x ** y
mypow(3, 2)
mypow(4, 2)
如果传递一个参数, x=3, y没有传递就是默认值2;
print(mypow(3))
如果传递2个参数, x=3, y有默认值2, 但是3会覆盖默认值,也就是求2的三次方;
print(mypow(2, 3))
可变参数
可变参数就是传入的参数个数是可变的,可以是 1 个、2 个到任意个,还可以是 0 个。*args
以数学题为例子,给定一组数字 a,b,c…,
请计算 a 2 + b 2 + c 2 + …
*nums用来接收多个变量/参数, 接收近来的nums是一个元组;
def numSquare(*nums):
"""
求n个数的平方
:param nums:
:return:
"""
# print(nums)
result = 0
for num in nums:
result += pow(num, 2)
print(result)
numSquare()
numSquare(1)
numSquare(1, 2, 3)
numSquare(3, 4, 5, 6, 7)
关键字参数
关键字参数允许传入 0 个或任意个含参数名的参数;
这些关键字参数在函数内部自动组装为一个 dict;
关键字参数用**kwargs;
**kwargs: 关键字参数, 接收的kwargs是一个字典;
def recordStudentInfo(name, sid, **kwargs):
"""
录入学生信息, 必填的内容姓名和学号, 其他的可以自己输入
"""
print("""
姓名: %s
学号: %s
"""%(name, sid))
for key, value in kwargs.items():
print("\t %s: \t%s" %(key, value))
recordStudentInfo("西部开源", '001', score=100, courses=['python', 'c', 'Linux'])
参数组合
参数组合是指可以必选参数、 默认参数、 可变参数和关键字参数一起使用。
参数定义的顺序必须是:必选参数、 默认参数、可变参数和关键字参数。
参数总结
二、练习
1.编程实现 9*9乘法表(循环嵌套的复习)
代码:
for it1 in r
ange(1,10):
for it2 in range(1,10):
item = it1 * it2
print('%s * %s = %s'%(it2,it1,item))
print('\n')
运行截图:
2.用函数实现求100-200里面所有的素数。
代码:
lis1 = []
lis2 = []
for it1 in range(100,201):
lis1.append(it1)
it = it1//2
for it2 in range(2,it):
if it1%it2 == 0:
lis2.append(it1)
break
print(set(lis1)-set(lis2))
运行截图:
3. 用函数实现输入某年某月某日,判断这一天是这一年的第几天?闰年情况也考虑进去。
代码:
def judge_leapyear(year):
if (year%4==0 and year%100 !=0) or year%400 == 0:
return True
else:
return False
#judge_leapyear(2020)
def judge_num_days(year,mouth,day):
if mouth == 1:
print('第%s天'%day)
elif mouth == 2 :
if judge_leapyear(year) and day<30:
day = day + 31
print('第%s天'%day)
else:
if day > 28:
print('日期错误')
else:
day = day + 31
print('第%s天' % day)
elif mouth < 13 and mouth>2:
if judge_leapyear(year):
t = tianshu(mouth)
day = t+day+1
print('第%s天' % day)
else:
t = tianshu(mouth)
day = t + day
print('第%s天' % day)
else:
print('日期错误')
def tianshu(mouth):
if mouth == 3:
return 59
elif mouth == 4:
return 90
elif mouth == 5:
return 120
elif mouth == 6:
return 151
elif mouth == 7:
return 181
elif mouth == 8:
return 212
elif mouth == 9:
return 243
elif mouth == 10:
return 273
elif mouth == 11:
return 304
elif mouth == 12:
return 334
year = int(input('请输入年:'))
mouth = int(input('请输入月:'))
day = int(input('请输入日:'))
judge_num_days(year,mouth,day)
4.平方等式
题目需求:对于一个十进制的正整数, 定义f(n)为其各位数字的平方和,如:
f(13) = 12 + 32 = 10
f(207) = 22 + 02 + 72 = 53
下面给出三个正整数k,a, b,你需要计算有多少个正整数n满足a<=n<=b,且k*f(n)=n
输入: 第一行包含3个正整数k,a, b, k>=1, a,b<=1018, a<=b;
输出:输出对应的答案;
范例:
输入: 51 5000 10000
输出: 3
代码:
a = int(input('请输入a:'))
b = int(input('请输入b:'))
k = int(input('请输入k:'))
def f(n): # 13
# 1. 先把数字转换为字符串;
n = str(n) # '13'
# 2. 计算字符串中每个数的平方
sum = 0
for item in n:
sum += int(item)**2
return sum
num=0
for it in range(a,b+1):
if k*f(it) == it:
num +=1
print(num)
运行截图:
5.质数对
题目描述:给定一个正整数,编写程序计算有多少对质数的和等于输入的这个正整数,并输出结果。输
入值小于1000。
如,输入为10, 程序应该输出结果为2。(共有两对质数的和为10,分别为(5,5),(3,7))
输入描述: 输入包括一个整数n,(3 ≤ n < 1000)
输出描述: 输出对数
示例1 :
输入: 10
输出: 2
代码:
num = int(input("N:")) # 10
1). 判断2~num之间有多少个质数?
def isPrime(num):
for i in range(2, num):
if num % i == 0:
return False
else:
return True
primeLi = [i for i in range(2,num) if isPrime(i)]
print(primeLi)
判断素数列表primeLi中有多少个素数对等于num
primePairCount = 0
for item1 in primeLi:
if (num -item1) in primeLi and item1 <= num-item1:
primePairCount += 1
print(primePairCount)
运行截图:
5.匿名函数
匿名函数指一类无须定义标识符的函数或子程序。Python用lambda语法定义匿名函数,只需用表达式而无需申明。(省略了用def声明函数的标准步骤)。
lambda函数的语法只包含一个语句,如下:
lambda函数能接收任何数量的参数但只能返回一个表达式的值
应用场合
1.函数作为参数传递
2.作为内置函数的参数
6.递归函数
什么是递归函数?
已知: 函数可以调用函数。结论: 一个函数在内部调用自己本身,这个函数就是递归函数。
例:求阶乘:( 阶乘的规律:n!=n*(n-1)! )
递归函数原理
常用的递归函数:斐波那契数列,汉诺塔问题
这里重点讲下汉诺塔问题
印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面。僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽
移动次数:有n个盘子,就得移动(2**n-1)次
话不多说,上代码;
moveCount = 0
def hanoi(n, a='A', b='B', c='C'):
"""
:param n:盘子个数
:param a:初始塔
:param b:缓存塔
:param c:目标塔
:return:移动次数
"""
if n == 1:
global moveCount
moveCount += 1
print(a, "--->", c)
else:
# 只是调用自己, 并没有真实的移动;
# 1). 打开冰箱门
hanoi(n - 1, a, c, b)
# 2). 把大象放进去
hanoi(1, a, b, c)
# 3). 把冰箱门close
hanoi(n - 1, b, a, c)
hanoi(3)
print("移动次数:", moveCount)