hexon
发布于 2025-10-28 / 5 阅读
0

八、函数基础

经过了前面第一个阶段的学习,基本对Python的语法特点与常用的基本数据类型熟悉了。从本篇开始,我们将进入第二阶段的学习,我们将学习一些诸如函数基础、文件操作、常用模块、模块与包等更加高级的内容,这部分内容其实也是高级编程语言中都有的内容,所以这里定义成基础进阶阶段。下面让我们从函数基础开启新的学习旅程。

一个程序有些功能代码可能会用到很多次,如果每次都写这样一段重复的代码,不但费时费力、容易出错,而且交给别人时也很麻烦,所以编程语言支持将代码以固定的格式封装(包装)成一个独立的代码块,只要知道这个代码块的名字就可以重复使用它,这个代码块就叫做函数(Function)

函数的本质是一功能代码块组织在一个函数名下,可以反复调用。

  1. 去重(函数可以减少代码的重复性。通过将重复的代码逻辑封装成函数,可以避免在不同的地方重复编写相同的代码)

  2. 解耦(函数对代码的组织结构化可以将代码分成逻辑上独立的模块,提高代码的可读性和可维护性,从而实现解耦)

# 案例1:

poke_types = ['♥️', '♦️', '♠️', '♣️']
poke_nums = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K', 'A']
for p_type in poke_types:
    for p_num in poke_nums:
        print(f"{p_type}{p_num}", sep="\t", end="")
    print()
  1. 美国人将函数称为“Function”。Function 除了有“函数”的意思,还有“功能”的意思,中国人将 Function 译为“函数”而不是“功能”,是因为C语言中的函数和数学中的函数在使用形式上有些类似。

  2. 函数是一种数学概念,它描述了两个数集之间的关系。通俗地说,函数就是一种将输入映射为输出的规则,它可以将一个或多个输入值转换为一个输出值。

  3. 如果定义一个函数 f(x) = x^2,那么当输入为 3 时,函数的输出值为 9。

1. 函数声明与调用

# (1) 函数声明
def 函数名():
  # 函数体【功能代码块】
  
# (2)函数调用
函数名()

案例1:

# 函数声明
def print_pokes():
    print("=" * 40)
    poke_types = ['♥️', '♦️', '♠️', '♣️']
    poke_nums = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K', 'A']
    for p_type in poke_types:
        for p_num in poke_nums:
            print(f"{p_type}{p_num}", end="")
        print()
    print("=" * 40)


# PEP8规范,函数声明与其他内容空两行
# 函数调用
print_pokes()
# 函数调用
print_pokes()
# 函数调用
print_pokes()

2. 函数参数

在编程中,函数的参数指的是函数定义中声明的变量,用于接收函数调用时传递的数据。参数允许我们将值或引用传递给函数,以便在函数内部使用这些值进行计算、操作或处理。(这里的值,理解为"字面量")

函数参数可以有多个,每个参数都有一个名称和类型。函数定义中的参数称为形式参数(或简称为形参),而函数调用时传递的实际值称为实际参数(或简称为实参)。

函数的参数允许函数在不同的上下文中接收不同的数据,并且增加了函数的灵活性和可复用性。通过合理使用函数参数,可以编写出更通用、灵活的函数。

# 案例1:
def cal(n):
    ret = 0
    for i in range(1, n + 1):
        ret += i
    print(ret)

cal(100)
# 这里要注意的是,你不传参数会报错的,不像JavaScript中一样,你不传不会报错
# cal()
  1. 内置函数:print、type都需要传参数

  2. 函数传递参数本质是变量赋值,且该变量只在函数运行时存在,运行结束销毁(这个话不严谨)

“函数参数的本质是 传递对象的引用,参数变量(形参)仅在函数作用域内有效,但通过引用修改的可变对象会保留变更。对象的生命周期由引用计数决定,与函数是否运行结束无关。”

补充:

在 Python 中,参数传递的机制既不是纯粹的值传递(Pass by Value),也不是纯粹的引用传递(Pass by Reference),而是一种独特的 “对象引用传递(Pass by Object Reference)。

Python 传递对象引用,行为由对象可变性决定。

不可变对象:类似值传递(函数内修改不影响外部)。

可变对象:类似引用传递(函数内修改影响外部)。

理解这一点对避免意外副作用至关重要!

【1】位置参数

位置参数是按照定义时的顺序进行传递的参数。调用函数时,实参的位置必须与形参的位置一一对应。

# 案例1
def add(x, y):  # x,y是形式参数,简称形参
    print(x + y)


# add(10, 20)  # 10,20是实际参数,简称实参
a = 1
b = 2
add(a, b)
# 函数调用时传递的位置参数不能多也不能少,JavaScript中可以少也可以多
# add(10 , 20 ,30)


# 案例2
def cal(start, end):
    ret = 0
    for i in range(start, end + 1):
        ret += i
    print(ret)

cal(100, 1000)


# 案例3

def send_email(recipient, subject, content):
    print("发送邮件...")
    print(f"收件人:{recipient}", )
    print(f"主题:{subject}")
    print(f"内容:{content}")


r = "alex@example.com"
s = "重要通知"
c = "Alex,你已经被解雇,明天不用来公司了!"
send_email(r, s, c)

r = "yuan@example.com"
s = "重要通知"
c = "yuan老师,您太辛苦了,给您涨薪十万!!"
send_email(r, s, c)

【2】默认参数

默认参数是在函数声明时为参数指定默认值。如果在函数调用时没有传递该参数的值,函数将使用默认值。(JavaScript中也有参数默认值)

# 案例1:
def show_info(name, age, height, weight, gender="女"):
    print("*" * 20)
    print(f"【姓名:{name}】")
    print(f"【年龄:{age}】")
    print(f"【身高:{height}】")
    print(f"【体重:{weight}】")
    print(f"【性别:{gender}】")
    print("*" * 20)


show_info("yuan", 18, 185, 60, "男")
show_info("alex", 18, 185, 60)

# 案例2
shopping_cart = [
    {
        "name": "mac电脑",
        "price": 14999,
        "quantity": 1
    },
    {
        "name": "iphone15",
        "price": 9980,
        "quantity": 3
    }
]

def cal_total(shopping_cart,discount=0.8):
    # 计算总价
    total = 0
    for goods in shopping_cart:
        total += goods["price"] * goods["quantity"]
    # 最后再算一个折扣
    total = round(total * discount)
    print(total)

cal_total(shopping_cart, 0.5)

注意,如果有默认参数,默认参数一定放在非默认参数后面

Python 的函数调用是基于位置参数的匹配规则,默认参数后如果还有非默认参数,会导致调用歧义。(但JavaScript中不一定放最后,它可传undefined替代,不过也建议是将默认参数放最后)

练习案例:累加和案例,传一个参数,则为end,传两个值,分别是start和end (复习)

# 别用sum命名,sum是内置函数
def cal(start, end=None):
    # 注意下这里推荐用 is
    if end is None:
        start,end = 1,start
    
    ret= 0
    for i in range(start, end + 1):
        ret+= i
    print(ret)

cal(100)
cal(1, 10)

【3】关键字参数

关键字参数是通过指定参数名来传递的参数。调用函数时,可以根据参数名来传递实参,而不必遵循形参的顺序。

# 这个案例只是举例,为了讲解关键字参数。实际上你都是非默认参数,你每个都要传的,按顺序传就是了,就和Java中一样
def show_info(name, age, height, weight):
    print("*" * 20)
    print(f"【姓名:{name}】")
    print(f"【年龄:{age}】")
    print(f"【身高:{height}】")
    print(f"【体重:{weight}】")
    print("*" * 20)

   
show_info("yuan", height=180, weight=60, age=18)
# show_info("alex", 48, weight=70, height=165)
show_info("alex", weight=70, height=165, age=48)
# 不是关键字参数就按位置匹配!

# 关键字参数一定要在位置参数后面!
# show_info("alex", weight=70, height=165, 48)

# 记忆:形参加值就是默认参数,实参加变量名就是关键字参数!
# 统一术语:形参分成非默认参数和默认参数,实参分成位置参数和关键字参数!

关键字参数一定要在位置参数后面

补充:

Java中没有这些花里胡哨的参数形式,它就是固定顺序传递,没有默认值。但是Java中可以通过方法重载、Builder模式来实现类似的效果!

关键字参数+默认参数

# 经典用法:默认参数+关键字参数
def show_info(name, age, height=None, weight=None, gender="男"):
    print("*" * 20)
    print(f"【姓名:{name}】")
    print(f"【年龄:{age}】")
    if height:
        print(f"【身高:{height}】")
    if weight:
        print(f"【体重:{weight}】")

    print(f"【性别:{gender}】")
    print("*" * 20)


show_info("yuan", 18, None, 60)
show_info("yuan", 18, weight=60)
show_info("june", 18, gender="女")
# 当函数有很多个默认参数时,此时实参使用关键字参数就很有用了!

练习:查询飞机票函数

# from是关键字,所以我们变量名加了_
def check_air_ticket(from_, to_, date="2025-7-1", airline_company="all", seat_class="经济舱", max_price=None):
    query = f"数据库查询:{date} :{from_}到{to_}的{airline_company}的{seat_class}机票"

    if max_price is not None:
        query += f",最高价格不超过{max_price}元"

    print(query)

# check_air_ticket("北京", "上海", max_price=2000)
check_air_ticket(from_="北京", to_="上海", seat_class="商务舱", max_price=2000)

【4】可变参数

可变数量参数允许函数接受不定数量的参数。在函数定义中,可以使用特殊符号来表示可变数量的参数,如*args用于接收任意数量的位置参数,**kwargs用于接收任意数量的关键字参数。

  • *args的用法

# * 计算时,代表乘法
print(3 * 4)
x,y,z = [1, 2, 3]
print(x,y,z)

# * 打包操作
x,y,*z = [1, 2, 3, 4, 5, 6]
print(z)  # z是列表

x,y,*z = (1, 2, 3, 4, 5, 6)
print(z)  # z还是列表,并不是元组!!!

# * 解包操作
numbers = [1, 2, 3]
print(*numbers)  # 等价于 print(1, 2, 3)


a, b, *c = [1, 2, 3, 4, 5]
print(type(a),type(c))

def add(*args):
    # print(type(args))  注意这是元组!
    print(*args)
    s = 0
    for i in args:
        s += i
    print(s)


add(1, 2, 3, 4)

案例:print函数

def print(self, *args, sep=' ', end='\n', file=None): # known special case of print
    """
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.
    """
    pass

注意:self参数不要管跳过,可变位置参数不一定要放最后!

  • **kwargs的用法

# ** 代表运算时,是次幂的意思
print(2**3)

# 用法1:函数调用的时候使用
def my_function(a, b, c):
    print(a, b, c)


a = {'a': 1, 'b': 2, 'c': 3}
# print(**a)  # 不能直接打印!
my_function(**a)  # 也叫字典解包


# 用法2:函数声明的时候使用
def send_email(recipient, subject, body, **kwargs):  # **kwargs处理默认参数太多的情况

    print(type(kwargs))  # 字典
    cc = kwargs.get('cc')
    bcc = kwargs.get('bcc')

    # 发送邮件的逻辑
    print("Sending email...")
    print(f"Subject: {subject}")
    print(f"Body: {body}")
    print(f"To: {recipient}")
    print(f"CC: {cc}")
    print(f"BCC: {bcc}")


r = "alex@example.com"
s = "重要通知"
c = "Alex,你已经被解雇,明天不用来公司了!"
# 示例调用
send_email(r, s, c, cc="bob@example.com", bcc="charlie@example.com")


# 用法3:*args和**kwargs结合
def test(a, *b, **c):
    print("a", a)
    print("b", b)
    print("c", c)

test(1, 2, 3, 4, x=10, y=20, z=30)

总结:

操作符

用途

收集类型

典型场景

*

位置参数/可迭代对象解包

列表/元组

函数 *args、解包列表

**

关键字参数/字典解包

字典

函数 **kwargs、合并字典

注意事项 * 和 ** 只能在赋值或函数参数中使用。

  • 打包时:

    • 赋值语句中的* 总是生成列表,即使源是元组;函数定义中的 *args(可变位置参数,始终收集为元组,即使传入的是列表或其他可迭代对象

    • ** 只能用于字典。

  • 解包时:

    • * 适用于任何可迭代对象(列表、元组、字符串等)。

    • ** 仅适用于字典(且键必须是字符串)。

# 示例1:基本打包
first, *middle, last = 1, 2, 3, 4, 5
print(first)  # 1
print(middle)  # [2, 3, 4]  ← 总是列表!
print(last)  # 5

# 示例2:即使源是元组
a, *b, c = (10, 20, 30, 40)
print(a)  # 10
print(b)  # [20, 30]  ← 还是列表!
print(c)  # 40

# 示例3:字符串(可迭代对象)
x, *y, z = "hello"
print(x)  # 'h'
print(y)  # ['e', 'l', 'l']  ← 还是列表!
print(z)  # 'o'

更多使用技巧参考:《Python中打包和解包操作符全面总结与示例

3. 函数作用域

作用域(Scope)是指在程序中定义变量或函数时,这些变量或函数可被访问的范围。在不同的作用域中,变量和函数的可见性和访问性是不同的。

当访问一个变量时,Python 会按照 LEGB 的顺序进行查找,直到找到第一个匹配的变量,然后停止查找。如果在所有作用域中都找不到变量的定义,就会引发 NameError。

  • L(Local):局部作用域。包括函数内部定义的变量和参数。在函数内部最先进行变量查找。

  • E(Enclosing):嵌套函数的父函数的作用域。如果在当前函数内部找不到变量,就会向上一层嵌套的函数中查找。

  • G(Global):全局作用域。在模块层次定义的变量,对于整个模块都是可见的。

  • B(Built-in):内置作用域。包括 Python 的内置函数和异常。

x = 10  # 全局作用域

def outer_func():
    x = 20  # 外部函数作用域   
    def inner_func():
        x = 30  # 内部函数作用域
        print(x)  # 在内部函数中访问变量 x
        
    inner_func()

outer_func()
print(x)  # 在全局作用域中访问变量 x

与函数相关的变量尽量放在函数中,防止全局变量污染

  • global关键字用于在函数内部声明一个变量为全局变量,表示在函数内部对该变量的修改将影响到全局作用域中的变量。例如

x = 10

def my_function():
    # 注意下这个语法哦,不是在赋值表达式前加global!
    global x
    x = 20
    print(x)

my_function()  # 输出结果为 20
print(x)  # 输出结果为 20

在函数my_function内部,使用global关键字声明了变量x为全局变量,然后对其进行了修改。这样,变量x的作用域扩展到了全局范围,所以在函数外部也可以访问到修改后的值。

  • nonlocal关键字用于在函数内部声明一个变量为非本地变量,表示在函数内部对该变量的修改将影响到上一级的嵌套作用域中的变量。例如:

def outer_function():
    x = 10
    print(id(x))
    
    def inner_function():
        nonlocal x  # 注意,外层函数要定义这个变量,否则会报错绑定不到x(但也可以在outer_function上一级再定义个函数里声明x,但是一定不会找全局的)
        print(id(x))
        x = 20
        print(id(x))  # 修改之后,地址变了,因为int是不可变类型
        print(x)
    
    inner_function()  # 输出结果为 20
    print(x)  # 输出结果为 20

outer_function()

inner_function内部,使用nonlocal关键字声明了变量x为非本地变量,然后对其进行了修改。这样,变量x的作用域扩展到了outer_function的作用域,所以在outer_function内部和外部都可以访问到修改后的值。

4. 函数返回值

函数的返回值是指函数执行完毕后,通过 return 语句返回给调用者的结果。

使用 return 语句可以将一个值或对象作为函数的返回值返回。这个返回值可以是任何有效的Python对象,例如数字、字符串、列表、字典等。函数执行到 return 语句时,会立即结束函数的执行,并将指定的返回值传递给调用者。

如果函内没有return,默认返回None,代表没有什么结果返回

下面是一个简单的函数示例,演示了如何使用返回值:

# 案例1
def add_numbers(a, b):
    s = a + b
    return s

result = add_numbers(3, 5)
print(result)  # 输出: 8

在案例1 中,add_numbers 函数接受两个参数 ab,将它们相加得到 sum,然后通过 return 语句将 sum 返回给调用者。在函数被调用时,返回值被赋值给变量 result,然后可以在后续的代码中使用。

# 返回多个子值
def login():
    name = "yuan"
    age = 18
    email = "123@qq.com"
    # return name, age, email  # 默认组织成元组对象
    
    # 也可以自己返回列表或者字典
    # return [name, age, email]
    
    #  这个是返回集合啊
    # return {
    #     name,
    #     age,
    #     email
    # }

    # 返回字典
    return {
        "name": name,
        "age": age,
        "email": email
    }

ret = login()
print(ret)  # 返回值有且仅有一个对象(可以是容器对象)

5. 匿名函数

如果函数只使用一次,就可以不单声明函数。一般只写一些简单的逻辑。

# 匿名函数
# 使用lambda声明函数,形参不用加括号,:后跟返回值。
ret = lambda x, y: x + y
# 这么玩,相当于还是声明了一个函数调用多次。
# print(ret(1, 2))
# print(ret(3, 4))

# 真正的匿名函数用法
ret = (lambda x, y: x + y)(100, 200)
print(300)
# 下面还想用lambda的逻辑必须重新定义

6. 常用的内置函数

Python 提供了许多内置函数,这些函数是 Python 语言的一部分,无需导入任何模块即可使用。

模式

功能

input([prompt])

从控制台获取用户的输入。

print()

一个或多个对象打印到控制台。

range(stop)

生成一个序列。

type(object)

返回对象的类型。

id(object)

获取对象的内存地址。

len(s)

返回对象s的长度。

str(object='')

将值转换为字符串。

repr(object)

将返回对象的字符串表示形式。

int(x=0)

将一个字符串或数字转换为整数。

float(x)

将一个字符串或数字转换为浮点数。

bool(x)

将值x转换为布尔值。

list([iterable])

将一个序列转换为列表。

tuple([iterable])

将一个序列转换为元组。

set([iterable])

返回一个新的集合对象。

bin(x)

将整数x转换为一个二进制字符串。

hex(x)

将整数x转换为十六进制字符串。

oct(x)

将整数x转换为八进制字符串。

abs(x)

返回x的绝对值。

pow(x,y[,z])

返回值x的y次幂,如果z给出,则对其结果取模。

max(iterable)

返回序列中最大的元素。

min(iterable)

返回序列中最小的元素。

round(number[, ndigits])

将一个数四舍五入到指定的精度。

sum(iterable[, start])

返回序列元素的总和。

divmod(a, b)

返回a和b的商和余数元组。

enumerate(iterable, start=0)

返回枚举对象。

eval()

将字符串作为表达式求值,并返回结果。

ord()

返回字符c的ASCII码。

chr(i)

返回整数i对应的ASCII字符。

reversed(seq)

返回序列seq的反转序列。返回的是一个 反向迭代器对象

filter(function, iterable)

过滤序列,过滤掉不符合条件的元素。

map(function, iterable, ...)

对序列中的每个元素应用function函数。

sorted(iterable[, key][, reverse])

返回一个列表,其中的元素按指定的键排序。

open()

打开一个文件,并返回一个文件对象。

# (1) range(10)
print(range(10))  # 迭代器
print(list(range(10)))

# (2) str
x = 100
print(str(x))  # '100'
l = [1, 2, 3]
d = {"name": "yuan"}
s1 = str(l)
s2 = str(d)
print(s1, type(s1))  # '[1,2,3]'
print(s2, type(s2))  # "{'name': 'yuan'}"

# (3) repr
l = [1, 2, 3]
d = {"name": "yuan"}
s1 = repr(l)
s2 = repr(d)
print(s1, type(s1))  # '[1,2,3]'
print(s2, type(s2))  # "{'name': 'yuan'}"

# 补充:repr和str区别(问AI吧)
# repr() → 开发者视角:精确、无歧义,适合调试。
# str() → 用户视角:简洁、友好,适合展示。
# 在自定义类中,建议同时实现 __repr__ 和 __str__ 以覆盖不同场景。
import datetime

now = datetime.datetime.now()
print(str(now), type(str(now)))
print(repr(now), type(repr(now)))

# (4) bool 注意零值
print(bool(0))
print(bool(""))
print(bool([]))
print(bool(dict()))
print(bool({}))  # 这个是集合

# (5) list tuple set
l = [1, 2, 3, 3, 2, 2]
# print(list(set(l)))

s = "hello yuan"
print(list(s))
print(tuple(s))
print(tuple(l))

# (6) bin hex oct 将十进制转换
x = 17
print(bin(x))
print(hex(x))
print(oct(x))

# (7) abs pow
x = -123
print(abs(x))
print(pow(2, 3))

# (8) max min sum:这三个要记住,不用再自己傻傻的写遍历了...
l = [12, 3, 4, 45]
print(max(l))
print(min(l))
print(sum(l))

print(max({4,5,1,8,9,3}))
print(min({4,5,1,8,9,3}))
print(sum({4,5,1,8,9,3}))

# 注意:对字典是对键操作!
print(max({2: "apple", 1: "banana", 3: "peach"}))
print(min({2: "apple", 1: "banana", 3: "peach"}))
print(sum({2: "apple", 1: "banana", 3: "peach"}))

# (9) round()
num = 3.1415926
print(round(num, 2))
print(round(num, 3))

# (10) divmod():返回的是元组,商和余数一起返回
print(5 / 2)
print(5 % 3)
print(divmod(5, 2))

# (11) enumerate
# n = 1
# for i in [111, 222, 333]:
#     print(f"{n}. {i}")
#     n += 1

l = [111, 222, 333]
# print(list(enumerate(l)))  # enumerate(l)返回是一个可迭代对象,转成列表后可以看到其实就是一个个元组
print(list(enumerate(l, 1)))

# 第二个参数指定起始序号
for index, val in enumerate(l, 1):
    print(index, val)

# (12) eval
# print(1 + 2 * 3 - (5 - 6) * 34)
exp = "1 + 2 * 3 - (5 - 6) * 34"
print(eval(exp))

# (13) ord chr
print(ord("a"))
print(ord("b"))
print(ord("z"))
print(ord("A"))

print(chr(122))
print(chr(97))

# (4) reversed
# l = [1,2,3]
# l.reverse()  # 列表的内置方法
# print(l)

l = [1,2,3]
print(reversed(l))  # 返回的是一个 反向迭代器对象
print(list(reversed(l)))

t = (33, 2, 18)
print(list(reversed(t)))  # 注意:是翻转,不是排序

高阶函数

定义:以函数作为参数或者以函数作为返回值的函数。

在 Python 中,函数是一等公民(First-Class Citizen),这意味着函数可以像普通变量一样被传递、赋值、作为参数或返回值使用。这种特性使得 Python 支持函数式编程范式,并能够实现高阶函数、闭包、装饰器等强大功能。

# 高阶函数的使用
def foo():
    print("foo")

def bar():
    print("bar")

# 高阶函数:实现不修改方法的情况下增强
def aop(f):
    print("start...")
    f()
    print("end...")

dec(foo)
dec(bar)

# filter函数用法
l = [23, 4,5,67,86,21]
# 使用列表推导式
print(i for i in l if i % 2 == 0)  # 可迭代对象
print([i for i in l if i % 2 == 0])

def get_even(item):
    return item % 2 == 0

print(list(filter(get_even, l)))

# 匿名函数
print(list(filter(lambda i:i%2==0, l)))

# map函数用法
l = [1, 2, 3, 4, 5, 6]
print(list(i**2 for i in l))

print(list(map(lambda i:i**2,l)))

filtermap 返回的也都是迭代器对象

# sorted函数使用(面试出现最多),一定注意它不是原地操作哦,是返回值才是排好序的!

# 列表对象内置排序方法
l = [34, 5, 6, 12, 41]
l.sort()  # 列表的内置函数
print(l)

# 案例1:
data01 = [("yuan", 18), ("alex", 48), ("peiQi", 32), ("alen", 78)]
# data01.sort()  # 这个比较没有意义,它是按元组中第一个元素,即字符串比较的。我们要的是根据年龄排序!
# print(data01)

# 方式1
# def my_order(item):
#     return item[1]
    
# print(sorted(data01, key=my_order))
# print(sorted(data01, key=my_order, reverse=True))

# 方式2
# print(sorted(data01, lambda item:item[1], True))  # 报错,必须使用关键字参数?因为这两个都是可选参数
print(sorted(data01, key=lambda item:item[1]))


# 案例2:
data02 = [
    {"name": "yuan", "age": 18, "height": 192},
    {"name": "alex", "age": 48, "height": 162},
    {"name": "peiQi", "age": 38, "height": 172},
    {"name": "rain", "age": 58, "height": 182},
]

# 按年龄排序
print(sorted(data02, key=lambda d:d.get("age")))

# 按身高排序
print(sorted(data02, key=lambda d:d.get("height")))

7. 案例【函数版】

(1)之前的案例函数化

# (1) 计算某段文本中元音字母出现的次数

def cal_num(text):
    count = 0
    for char in text:
        if char.lower() in "aeiou":
            count += 1
    return count

# 在 Python 中,函数必须在使用之前定义(声明)。这意味着,如果你尝试在函数定义之前调用它,Python 会抛出 NameError,因为 Python 会在运行时解释代码,且在执行到调用函数的地方之前,并不知道该函数的存在。
data = input("请输入一段英文文本:")
print(cal_num(data))

# (2) 计算初始本金为1万,年利率为0.0325的情况下,需要多少年才能将本金和利息翻倍,即本金和利息的总和达到原来的两倍。

def cal_year(base, back, rate=0.0325):
    total = base

    year = 0
    while(total < back):
        total = total + total * rate
        year += 1
    return year

print(cal_year(10000, 20000))
print(cal_year(10000, 100000, 0.03))

# (3) 编写一个程序,生成斐波那契数列的第20个数字(斐波那契数列是指从0和1开始,后面的每一项都是前两项的和)

def fib(n):
    if n <= 1:
        return n
    first = 0
    second = 1
    # 这里千万别写成了 --n > 0,因为python中没有前--这个操作符!
    while(n > 1):
        # second = first + second
        # first = second - first
        # python中可以么玩
        first, second = second, first + second
        n -= 1
    return second

print(fib(20))  # 第20个斐波那契数就是数列n + 1位置上的

# (4) 打印n*n矩阵

def print_matrix(n):
    for i in range(1, n + 1):
        for j in range(1, n + 1):
            print(f"{i + j}\t", end="")
        print()

print_matrix(5)

# (5) 重写 max min函数

num = [23, 2, 5, 66, 76, 12, 88, 23, 65]

def my_max(numbers):
    max_value = numbers[0]
    for i in numbers:
        if i > max_value:
            max_value = i

    return max_value

print(my_max(num))
print(max(num))

# (6) 获取字典中最大值和对应键

def get_max_val(my_dict):
    max_val = 0
    max_val_key = None
    for key, val in my_dict.items():
        if val > max_val:
            max_val = val
            max_val_key = key

    return (max_val_key, max_val)


data = {'A': 10, 'B': 5, 'C': 35, 'D': 20}

print(get_max_val(data))

# (7) 查询列表元素重复次数

def cal_val_num(l):
    count_dict = {}

    for i in l:
        if i in count_dict:
            # count_dict[i] +=1
            count_dict[i] = count_dict[i] + 1
        else:
            count_dict[i] = 1

    return count_dict


my_list = [1, 2, 3, 2, 1, 3, 4, 5, 2, 1]

print(cal_val_num(my_list))

# (8)商品推荐函数重写

def recommend_hobby(name):
    hobby_dict = {
        "yuan": {"pizza", "salad", "ice cream", "臭豆腐", "榴莲" },
        "alex": {"螺狮粉", "臭豆腐", "榴莲", "💩", 'pizza'},
        "peiQi": {"螺狮粉", "臭豆腐", "榴莲", "apple"},
    }
    

     # 删除当前推荐人的hobby_set
    origin_hobby = hobby_dict.pop(name, None)  # 指定默认值,防止keyError
    if origin_hobby is None:
        return []

    # {} 默认是字典,集合要用set()
    recommend_hobby_set = set()

    for name, hobby_set in hobby_dict.items():
        if len(origin_hobby.intersection(hobby_set)) >= 2:
            recommend_hobby_set.update(hobby_set - origin_hobby)

    return list(recommend_hobby_set)

print(recommend_hobby("peiQi"))
print(recommend_hobby("yuan"))
print(recommend_hobby("alex"))

(2)客户关系管理系统【函数版】

# 初始化客户信息列表
customers = {
    1001: {
        "name": "Alice",
        "age": 25,
        "email": "alice@example.com"
    },
    1002: {
        "name": "Bob",
        "age": 28,
        "email": "bob@example.com"
    },
}


# 添加客户功能
def add_customer():
    # (1) 添加客户 append

    id = int(input("请输入添加客户的ID:"))

    if id in customers:  # "1001" in {1001:...}
        print("该ID已经存在!")
    else:

        name = input("请输入添加客户的姓名:")
        age = input("请输入添加客户的年龄:")
        email = input("请输入添加客户的邮箱:")

        new_customer = {
            "name": name,
            "age": age,
            "email": email
        }
        # customers[id] = new_customer
        customers.update({id: new_customer})

        print(f"添加客户{name}成功!")
        print("当前客户:", customers)


# 删除客户
def del_customer():
    # (2) 删除客户
    del_customer_id = int(input("请输入删除客户的ID:"))
    if del_customer_id in customers:

        customers.pop(del_customer_id)
        print(f"删除{del_customer_id}客户成功!")
        print("当前客户:", customers)
    else:
        print("该ID不存在!")


# 修改客户
def update_customer():
    # (3) 修改客户
    update_customer_id = int(input("请输入修改客户的ID:"))

    if update_customer_id in customers:

        name = input("请输入修改客户新的姓名:")
        age = input("请输入修改客户新的年龄:")
        email = input("请输入修改客户新的邮箱:")

     
        customers[update_customer_id].update({"name": name, "age": age, "email": email})
      
        print(f"{update_customer_id}客户修改成功!")
        print("当前客户:", customers)
    else:
        print("该ID不存在!")


# 查询一个客户

def query_one_customer():
    # (4) 查看某一个客户
    query_customer_id = int(input("请输入查看客户的ID:"))
    if query_customer_id in customers:
        customerD = customers[query_customer_id]
        print(f"姓名:{customerD.get('name')},年龄:{customerD.get('age')},邮箱:{customerD.get('email')}")
    else:
        print("该客户ID不存在!")


def show_all_customers():
    # (5) 遍历每一个一个客户信息
    # if len(customers) == 0:
    if customers:
        for key, customerDict in customers.items():
            print(
                f"客户ID:{key},姓名:{customerDict.get('name'):10},年龄:{customerDict.get('age')},邮箱:{customerDict.get('email')}")
    else:
        print("当前没有任何客户信息!")

# 退出程序
def exit_program():
    print("程序已退出,谢谢使用!")

def main():
    while 1:
        print("""
               1. 添加客户
               2. 删除客户
               3. 修改客户
               4. 查询一个客户
               5. 查询所有客户
               6. 退出

            """)
        choice = input("请输入您的选择:")

        # 这个代码就关注这里即可,实现类似swich-case的方法
        handler = {
            "1": add_customer,
            "2": del_customer,
            "3": update_customer,
            "4": query_one_customer,
            "5": show_all_customers,
            # 这个是AI写的
            "6": exit_program,
        }

        # 这里我加了个判断
        if handler.get(choice):
            if choice == "6":  # 如果选择了6,直接退出
                handler.get(choice)()  # 调用退出函数
                break  # 退出while循环
            else:
                handler.get(choice)()  # 调用其他功能


# Python中函数可以重复定义后面的会覆盖前面的,这里我使用的是Python 3.10+ 的 match-case
def main():
    while True:
        print("""
               1. 添加客户
               2. 删除客户
               3. 修改客户
               4. 查询一个客户
               5. 查询所有客户
               6. 退出
            """)
        choice = input("请输入您的选择:")

        # 使用 match-case 来模拟 switch-case
        match choice:
            case "1":
                add_customer()
            case "2":
                del_customer()
            case "3":
                update_customer()
            case "4":
                query_one_customer()
            case "5":
                show_all_customers()
            case "6":
                exit_program()
                break  # 退出while循环
            case _:
                print("无效的选择,请重新输入!")


main()

8. 今日作业

1.编写一个函数,获取用户输入圆的半径。使用圆的周长和面积公式计算并打印出输入半径的圆的周长和面积。

def print_circle(r):
    l = 2 * 3.14 * r
    s = 3.14 * (r ** 2)
    print(f"半径为:{r}的圆, 周长是: {l}, 面积是: {s}")

print_circle(2)

2.编写一个函数,计算BMI并给出健康建议

def cal_bmi(height, weight):
    bmi = weight / (height ** 2)
    if bmi < 18.5:
        advice = f"您的BMI为 {bmi:.3},体重过轻,建议增加营养摄入。"
    elif 18.5 <= bmi < 24:
        advice = f"您的BMI为 {bmi:.3},体重正常,继续保持健康的生活方式。"
    elif 24 <= bmi < 28:
        advice = f"您的BMI为 {bmi:.3},体重过重,建议适当控制饮食并增加运动。"
    else:
        advice = f"您的BMI为 {bmi:.3},体重肥胖,建议减少高热量食物摄入并增加运动量。"
    return advice

cal_bmi(1.77, 51)

3.编写一个函数,输入长度,获取该长度的随机验证码

import random
import string

def get_randomcode(length):
    char = string.ascii_letters + string.digits
    count = 0
    randomCodes = ""
    while count < length:
        code = random.choice(char)
        randomCodes += code
        count += 1
    return randomCodes

get_randomcode(4)

4.编写一个函数,计算列表中所有元素的平均值的函数,参数为列表

def get_avg(lst):
    return sum(lst) / len(lst)

l = [1, 2, 3, 4]
get_avg(l)

5.编写一个函数,接收一个整数作为参数,返回该整数的阶乘

def get_factorial(n):
    total = 1
    for i in range(1, n + 1):
        total *= i
    return total

get_factorial(10)

6.程序执行结果

def foo(x):
    x[0] = 100
    x.append(4)
    print(x)

l = [1, 2, 3]
foo(l)  # [100, 2, 3, 4]
print(l) # [100, 2, 3, 4]

7.程序执行结果

x = 10

def my_func():
    print(x)

def outer():
    x = 20
    my_func()

outer()  # 10

8.执行

code = "sum([2 * 3 + 6, (5 - 9) + 7 - 2, 13 * 4 - 11])"
# 执行code代码

ret = eval(code)
print(ret)

9.计算列表[11,22,33,44,55]的每一个元素的平方的和

l = [11,22,33,44,55]
sum(map(lambda i:i**2, l))

10.给定一个字符串列表 ['apple', 'banana', 'cherry', 'date']

  • 使用 filter() 过滤出所有长度小于等于5的字符串。

  • 使用 sorted() 对列表进行按照长度进行降序排序。

s = ['apple', 'banana', 'cherry', 'date']
list(filter(lambda i:len(i) <=5, s))

# 这个语法注意下,先是可迭代对象,再是关键字参数,而且它返回的就是列表
print(type(sorted(s, key=lambda i:len(i), reverse=True)))
sorted(s, key=lambda i:len(i), reverse=True)

11.给定一个字典列表 [{ 'name': 'Alice', 'age': 25 }, { 'name': 'Bob', 'age': 30 }, { 'name': 'Charlie', 'age': 20 }]

  • 使用 filter() 过滤出所有年龄大于等于25的人。

  • 使用 filter() 过滤出所有名字以aA开头的

  • 使用 map() 提取每个字典中的名字字段的长度,并返回新的列表。

dict_list = [
    { 'name': 'Alice', 'age': 25 }, 
    { 'name': 'Bob', 'age': 30 }, 
    { 'name': 'Charlie', 'age': 20 }
]
print(list(filter(lambda d:d.get("age") > 25, dict_list)))
print(list(filter(lambda d:d.get("name").lower().startswith("a"), dict_list)))
print(list(map(lambda d:len(d.get("name")), dict_list)))

12.实现程序要求功能

def a():
    print("aaa")


def b():
    print("bbb")


def c():
    print("ccc")


def d():
    print("ddd")


def e():
    print("eee")


func_list = [a, b, c, d, e]
# 调用列表中第三个函数
func_list[2]()


func_dict = {
    "a": a,
    "b": b,
    "c": c,
    "d": d,
    "e": e,
}
# 调用字典中的d函数
func_dict.get("d")()

13.收银系统函数版(day06的商品管理系统作业)

// ...