函数

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的内建函数姑且不算了。现在之所以使用函数,主要是:

  1. 降低编程的难度(分而治之的思想)
  2. 代码重用。避免了重复劳动,提供了工作效率。

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<=10
18, 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)

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值