第4章 函数与模块化编程 - 图1
第4章 函数和模块化编程.pptx

函数

  1. name()
  2. input() # 无参函数
  3. print('Hello') # 有参函数

能力点1:定义和调用函数的能力

函数是可重复使用的,用来实现单一,或相关联功能的代码段。
函数能提高应用的模块性、代码的重用性和可维护性
内置函数,比如print()、input()
自己创建函数,用户自定义函数

示例 4.1 判断素数

  1. 输入一个正整数n
  2. 如果这个数小于2
    1. 不是素数
  3. 否则
    1. 遍历从2到n-1
      1. 判断其中有没有n的因子
        1. 如果存在因子
          1. 输出不是素数
          2. 终止循环
    2. 如果遍历正常完成,即不存在因子
      1. 输出是素数 ```python n = int(input()) if n < 2: print(f’{n}不是素数’) # 0和1不是素数 else: for i in range(2, n): # 取2到n-1这间的每个数 if n % i == 0: # n能否被当前数整除,有整除则不是素数 print(f’{n}不是素数’) break # 判定n不是素数后不需要继续判定i后面的数字,结束循环,提高效率 else: # 未遇到break时执行else子句,此时一定是素数 print(f’{n}是素数’)
  1. ```python
  2. # 函数的定义
  3. def is_prime():
  4. """判断是否为素数,返回布尔值"""
  5. n = int(input())
  6. if n < 2: # 0和1不是素数
  7. return False # 返回值
  8. for i in range(2, n):
  9. if n % i == 0:
  10. return False # 返回值
  11. else:
  12. return True # 返回值
  13. print(is_prime()) # 函数的调用

函数定义,调用和返回值

函数定义时应该加文档字符串,说明函数的作用,参数数量、类型、返回值数量和类型等信息。

  1. # 函数的定义
  2. def is_prime(n): # 括号里为传入的参数相当于赋值n = 100
  3. """接收一个整数为参数,判断是否为素数,返回布尔值"""
  4. if n < 2: # 0和1不是素数
  5. return False # 返回值
  6. for i in range(2, n):
  7. if n % i == 0:
  8. return False # 返回值
  9. else:
  10. return True # 返回值
  11. print(is_prime(100)) # 函数的调用
  1. # 提高算法效率
  2. def is_prime(n): # 括号里为传入的参数相当于赋值n = 100
  3. """接收一个整数为参数,判断是否为素数,返回布尔值"""
  4. if n < 2: # 0和1不是素数
  5. return False # 返回值
  6. for i in range(2, int(n ** 0.5) + 1): # range参数必须为整数100-->10
  7. if n % i == 0:
  8. return False # 返回值
  9. else: # else与for对齐,是循环语句的了句,与if无关
  10. return True # 返回值
  11. print(is_prime(100)) # 函数的调用

能力点2:为函数传递参数的能力

定义函数时有几个参数,调用函数时就需要传递几个参数
掌握位置传递参数

多参数,默认值参数

  1. print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
  2. int(x, base=10)
  1. def power(x, n=2): # 多个参数,默认值参数
  2. """接收一个数值型参数x,一个默认值参数n,n没有传入值时n=2
  3. 计算x的n次幂,返回计算结果
  4. """
  5. result = 1
  6. for i in range(n):
  7. result = result * x # 注意乘的是x 不是i
  8. return result # 返回计算结果
  9. print(power(2, 10)) # 传入2个参数时,n= 10
  10. print(power(2)) # 传入1个参数时,n用默认值

包裹传递参数

拆包就是将一个可迭代对象(range,列表,元组,字典,集合,字符串等)中的多个元素拆为多个对象

  1. print(*'Hello') # H e l l o
  2. print(*range(5)) # 0 1 2 3 4
  3. args = ('Tom', 18, 'Male')
  4. print(*args) # Tom 18 Male,可用此方法输出可迭代对象中的数据,空格分隔
  5. # 字典用*解包得到的是键
  6. dict = {'u_name': 'Tom', 'age': 18, 'gender': 'Male'}
  7. func(*dict) # u_name age gender,
  8. # 字典用**解包得到的是值
  9. dict = {'u_name': 'Tom', 'age': 18, 'gender': 'Male'}
  10. func(**dict) # Tom 18 Male,字典用**解包得到的是键
  1. def func(u_name, age, gender):
  2. print(u_name, age, gender)
  3. args = ('Tom', 18, 'Male')
  4. func(*args) # Tom 18 Male

能力点3:利用函数简化程序逻辑

  1. def is_prime(n):
  2. """接收正整数n,判断是否为素数,返回布尔值"""
  3. if n < 2:
  4. return False # 0和1不是素数
  5. for i in range(2, n): # 遍历(2, n-1)中的数
  6. if n % i == 0: # 若在(2, n-1)中存在因子则不是素数
  7. return False # 不是素数时返回False
  8. else: # for语句遍历(2, n-1)中所有数,未发现因子存在时,才是素数
  9. return True # 素数时返回True
  10. if __name__ == '__main__':
  11. num = int(input()) # 接收用户输入并转成整数
  12. if is_prime(num): # 调用函数
  13. print(f'{num}是素数')
  14. else: # 调用函数
  15. print(f'{num}不是素数')

示例4.2 哥德巴赫猜想

数学领域著名的“哥德巴赫猜想”的大致意思是:
任何一个大于2的偶数总能表示为两个素数之和。
例如:24=5+19,其中5和19都是素数。本实验的任务是设计一个程序,验证20亿以内的偶数都可以分解成两个素数之和。
输入一个大于2的正整数,当输入为偶数时,在一行中按照格式“N = p + q”输出N的素数分解,其中p 、 q均为素数且p ≤ q。
因为这样的分解可能不唯一(例如24还可以分解为7+17),要求必须输出所有解中p最小的解。当输入为奇数时,输出’Data error!’ 。‪‬‪‬‪‬‪‬‪‬‮‬‪‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬
输入格式
输入一个不小于2的正整数‪‬‪‬‪‬‪‬‪‬‮‬‪‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬
输出格式
当输入为偶数时,按照格式“N = p + q”输出N的素数分解;
当输入为奇数时,输出’Data error!’ 。

  1. 输入一个正整数n
  2. 设置一个标记变量
  3. 如果输入是偶数
    1. 从小到大遍历从1到n for p in range(1, n):
      1. 从小到大遍历从1到n for q in range(1,n):
        1. 如果 p 是素数,且q是素数,且p+q==n
          1. 输出n=p+q
          2. 改变标记变量值
          3. 结束内层循环
      2. 根据标记变量的值确定是否找到了解,如果找到了解
        1. 结束外层循环
  4. 如果输入不是偶数

    1. 输出’Data error!’

  5. ```python def is_prime(n): # 判断素数的函数 if n < 2:

    1. return False # 0和1不是素数

    for i in range(2, n):

     if n % i == 0:
         return False
    

    else:

     return True
    

用标记变量和2个break才能提前退出两重循环

若不定义素数函数,则需在3重循环

N = int(input()) # 接收用户输入并转成整数 flag = False if N % 2 == 0: for p in range(N): for q in range(N): if is_prime(p) and is_prime(q) and p + q == N: print(“{} = {} + {}”.format(N, p, N - p)) flag = True break if flag: break else: print(‘Data error!’)

```python
def is_prime(n):
    """接收正整数n,判断是否为素数,返回布尔值"""
    if n < 2:
        return False       # 0和1不是素数
    for i in range(2, n):  # 遍历(2, n-1)中的数
        if n % i == 0:     # 若在(2, n-1)中存在因子则不是素数
            return False   # 不是素数时返回False
    else:   # for语句遍历(2, n-1)中所有数,未发现因子存在时,才是素数
        return True        # 素数时返回True


def goldbach(n):
    """接收正整数n,若为偶数,输出分解为素数加和的表达式
    若不是偶数时,输出'Data error!'"""
    if n % 2 == 0:                               # 若为偶数
        for p in range(n//2 + 1):                # 只遍历一半以前的数
            if is_prime(p) and is_prime(n - p):  # 若p为素数,且n-p也是素数
                return f'{n} = {p} + {n-p}'      # 返回表达式字符串,遇return结束循环
    else:                                        # 若为奇数
        return 'Data error!'                     # 返回'Data error!'


if __name__ == '__main__':
    num = int(input())    # 接收用户输入并转成整数
    print(goldbach(num))  # 调用函数,输出函数返回值

能力点4 变量作用域

1. 全局变量

在模块层次(函数外)定义的变量
1.1 在函数内部可以访问(做为参数或出现在赋值号右侧)

def car(year, model):
    """参数为年份和型号,返回字符串"""
    auto_brand = brand  # brand是全局变量,函数内可以访问和使用
    print(auto_brand)   # 输出 宝马
    return f'这是一辆{year}年生产,型号是{model}的{brand}牌汽车。'


brand = '宝马'         # 全局变量
ls = input().split()  # 根据空格切分输入字符串为列表
print(car(*ls))       # 调用函数,取列表中的全部数据做参数

2021 525i
宝马
这是一辆2021年生产,型号是525i的宝马牌汽车。

1.2 在函数内部给全局变量赋值会创建新的同名局部变量,影响函数外部全局变量的值

def car(year, model):
    """参数为年份和型号,返回字符串"""
    brand = '劳斯莱斯'  # 创建新的局部变量名brand,不影响函数外部的值
    print(brand)       # 输出 劳斯莱斯
    return f'这是一辆{year}年生产,型号是{model}的{brand}牌汽车。'


brand = '宝马'        # 全局变量
ls = input().split()  # 根据空格切分输入字符串为列表
print(car(*ls))       # 调用函数,取列表中的全部数据做参数
print(brand)          # 宝马

2021 525i
劳斯莱斯
这是一辆2021年生产,型号是525i的劳斯莱斯牌汽车。
宝马

1.3 函数内修改全局变量的值可以在变量名前加关键字 global

def car(year, model):
    """参数为年份和型号,返回字符串"""
    global brand
    brand = '劳斯莱斯'  # 全局变量名brand绑定到新对象上,相当于修改了值
    print(brand)   # 输出 劳斯莱斯
    return f'这是一辆{year}年生产,型号是{model}的{brand}牌汽车。'


brand = '宝马'         # 全局变量
ls = input().split()  # 根据空格切分输入字符串为列表
print(car(*ls))       # 调用函数,取列表中的全部数据做参数
print(brand)          # 劳斯莱斯

2021 525i
劳斯莱斯
这是一辆2021年生产,型号是525i的劳斯莱斯牌汽车。
劳斯莱斯

1.4 在函数内部可用原地操作方法修改可变类型全局变量的值

def car(year, model):
    """参数为年份和型号,返回字符串"""
    brand_ls.append('劳斯莱斯')  # 全局变量brand_ls原地增加新元素
    print(brand_ls)   # 输出 ['宝马', '劳斯莱斯']
    return f'这是一辆{year}年生产,型号是{model}的{brand_ls[1]}牌汽车。'


brand_ls = ['宝马']    # 可变数据类型全局变量
ls = input().split()  # 根据空格切分输入字符串为列表
print(car(*ls))       # 调用函数,取列表中的全部数据做参数
print(brand_ls)       # ['宝马', '劳斯莱斯']

2019 745li
[‘宝马’, ‘劳斯莱斯’]
这是一辆2019年生产,型号是745li的劳斯莱斯牌汽车。
[‘宝马’, ‘劳斯莱斯’]

2. 局部变量

在函数内部定义的变量,用完就销毁
在函数外部无法访问

def car(year, model):
    """参数为年份和型号,返回字符串"""
    brand = '劳斯莱斯'  # 局部变量名brand,只有函数内部可访问
    print(brand)   # 输出 劳斯莱斯
    return f'这是一辆{year}年生产,型号是{model}的{brand}牌汽车。'


ls = input().split()  # 根据空格切分输入字符串为列表
print(car(*ls))       # 调用函数,取列表中的全部数据做参数
print(brand)          # NameError: name 'brand' is not defined

2019 745li

劳斯莱斯
这是一辆2019年生产,型号是745li的劳斯莱斯牌汽车。
print(brand) # 劳斯莱斯
NameError: name ‘brand’ is not defined

算法1:递归

示例4.3 阶乘

def fact(n):
    if n == 0:      # 必须有一个终止条件
        return 1    # 此时返回值确定值
    else:
        return n * fact(n - 1)  # 当前数n的阶乘等于n与前一个数阶乘的乘积

num = int(input())
print(fact(num))

示例4.4 猴子吃桃

描述
猴子第1天摘了一堆桃子吃了一半又多一个,第2天吃了剩下的一半又多一个,…,第10天早上时发现只有1个桃子了。问第1天摘了多少?
第10天余1个桃子
第9天余4个桃子,2 (peach(10) + 1)
第8天余10个桃子,2
(peach(9) + 1)
第7天余22个桃子,2 (peach(8) + 1)
第6天余46个桃子,2
(peach(7) + 1)
第5天余94个桃子,2 (peach(6) + 1)
第4天余190个桃子,2
(peach(5) + 1)
第3天余382个桃子,2 (peach(4) + 1)
第2天余766个桃子,2
(peach(3) + 1)
第1天余1534个桃子,2 * (peach(2) + 1)

  1. 定义函数
    1. 如果是第10天
      1. 返回值只剩1个桃子
    2. 否则返回桃子数量为后面一天桃子数量加1乘2
  2. 输出第一天数量
def peach(day):
    if day == 10:   # 必须有一个终止条件
        return 1    # 此时返回值确定值
    else:
        return 2 * (peach(day + 1) + 1)  # 后面一天桃子数量加1乘2,调用函数本身,规模变小


print(peach(1))

递归有深度限制

递归有层次限制,1000左右,操作系统限制4000左右
循环没有次数限制,建议优先用循环

def peach(day):
    if day == 1000:
        return 1
    else:
        return 2 * (peach(day + 1) + 1)  # 后面一天桃子数量加1乘2


print(peach(1))
if day == 1000:<br />RecursionError: maximum recursion depth exceeded in comparison
import sys

sys.setrecursionlimit(3900)  # 用sys中的方法改变递归栈深度


def peach(day):
    if day == 3494:
        return 1
    else:
        return 2 * (peach(day + 1) + 1)  # 后面一天桃子数量加1乘2


print(peach(1))

94383506707880119754754048645789755724090203656771185206515156748743982508217352707360950352103421591392896498830209795074697702627207367107553591516785958153633365493734160057486717116758000333344743150268694082271796533226044514673879152706390649090930408892486471407502577264049586455950418875351028786460850838033103255904072590971746322449835583505006495257190229742056919947782449887434632228091520901431007070898179709128949362654286389236116545365469172749138337714491412347814682558371778807380649351116805460001779164439400065150382816635537204755944969133012431907069121740022804757349675866507489546453676099734220985844431391170771641784263483115325656146276118096654473925891319406869669292301512471448775025920358512979563961763836158573622695029158118334029288843123682428012267452044399619835290721915520457633768409034208684591253260984575484121420242955370959467532290571598837821147509192959971781615483174639379997621428287965319618190362323300011587566803587183592336332476372644502477398385031616817081718676789759536001110245374

import sys

sys.setrecursionlimit(3900)


def peach(day):
    if day == 3495:
        return 1
    else:
        return 2 * (peach(day + 1) + 1)  # 后面一天桃子数量加1乘2


print(peach(1))

Process finished with exit code -1073741571 (0xC00000FD)

循环方法无层次限制

num = 1
for i in range(9, 0, -1):
    num = (num + 1) * 2
    print(f'第{i}天有{num}个桃子')

第9天有4个桃子
第8天有10个桃子
第7天有22个桃子
第6天有46个桃子
第5天有94个桃子
第4天有190个桃子
第3天有382个桃子
第2天有766个桃子
第1天有1534个桃子

num = 1
for i in range(999, 0, -1):
    num = (num + 1) * 2
print(f'第{i}天有{num}个桃子')

第1天有16072629107794009814226375735900027158421072175583004111656255825555265766874041837397975682235437871913920093763297202377807179285384710653976866362047862205901851662236346478131611907593556712816931273229569712475372911901098151338748315919115594371856794716529813251490644747478936580255808502104062个桃子

能力点5:匿名函数lambda

def f(x):
    return len(x)


ls = ['58', '01', '9', '920']
print(sorted(ls))                        # ['01', '58', '9', '920']
print(sorted(ls, key=int))               # ['01', '9', '58', '920']
print(sorted(ls, key=f))                 # ['9', '58', '01', '920']
print(sorted(ls, key=lambda x: len(x)))  # ['9', '58', '01', '920']
print(sorted(ls, key=lambda x: int(x)))  # ['01', '9', '58', '920']

能力点6:为函数加文档测试

# 利用文档测试可以检验函数的输出是否与预期相符
# >>>后面空一个字符加函数的调用,后面一行写期望的输出值
def is_prime(n):
    """接收正整数n,判断是否为素数,返回布尔值.
    >>> is_prime(1)
    False
    >>> is_prime(2)
    True
    >>> is_prime(3)
    True
    >>> is_prime(13)
    True
    >>> is_prime(25)
    False
    """
    if n < 2:
        return False       # 0和1不是素数
    for i in range(2, n):  # 遍历(2, n-1)中的数
        if n % i == 0:     # 若在(2, n-1)中存在因子则不是素数
            return False   # 不是素数时返回False
    else:   # for语句遍历(2, n-1)中所有数,未发现因子存在时,才是素数
        return True        # 素数时返回True


if __name__ == '__main__':
    num = int(input())  # 接收用户输入并转成整数
    if is_prime(num):   # 调用函数
        print(f'{num}是素数')
    else:               # 调用函数
        print(f'{num}不是素数')
# 利用文档测试可以检验函数的输出是否与预期相符
# >>>后面空一个字符加函数的调用,后面一行写期望的输出值
import math


def area_of_circle(radius):
    """接收一个表示圆半径的浮点数为参数,利用Math库中的圆周率计算面积.
    返回表示面积的浮点数.
    >>> area_of_circle(5)
    78.54
    >>> area_of_circle(3)
    28.27
    """
    area = math.pi * radius * radius  # 计算面积
    return round(area, 2)  # 返回面积,保留小数点后2位


if __name__ == '__main__':
    r = float(input())        # 输入转浮点数
    print(area_of_circle(r))  # 调用函数,传递半径,计算面积
def is_leap(year):
    """接收一个整数表示年份,判断是否为闰年,返回布尔值.
    >>> is_leap(1995)
    False
    >>> is_leap(1900)
    False
    >>> is_leap(1996)
    True
    >>> is_leap(2000)
    True
    """
    if year % 4 == 0 and year % 100 != 0 or year % 400 == 0:
        return True
    else:
        return False


if __name__ == '__main__':
    year = int(input())
    print(is_leap(year))