【Python】函数与模块化编程

1. 函数进阶

1.1. 参数传递

1.1.1. 位置参数

函数调用时参数按照定义时的顺序传递

python 复制代码
# 位置参数
def greet(name, greeting):
    print(f"{greeting}, {name}!")
greet("Alice", "Hello")  # 输出: Hello, Alice!

1.1.2. 默认值参数

● 形参设定默认值称为 默认参数

● 调用函数时,如果没有传入默认参数对应的实参,则实参使用默认值

● 默认参数在调用的时候可以不传递,也可以传递

● 默认参数一定要在参数的最后

python 复制代码
def say_hello(name='张三'):# 形参
    """
    给男神打招呼
    :param name:
    :return:
    """
    print('hello ', name)

	# 调用时不传递参数,使用默认值
	say_hello()
	# 调用时传递参数
	say_hello('张三')
python 复制代码
def say_hello(score, name='张三'):# 默认参数放在参数最后面
    """
    给男神打招呼
    :param name:
    :return:
    """
    print('hello %s'%(name))

say_hello(90, '张三')

1.1.3. 关键字参数

● 调用函数时实参可以指定对应的形参称为关键字参数

● 使用关键字参数调用可以改变传递参数的顺序

python 复制代码
def say_hello(name, age, score):
    print('姓名:%s,年纪:%d,分数:%f'%(name,age,score))
say_hello(name='张三',age=37,score=70.5)

# 改变参数传递的顺序
say_hello(score=70,age=30,name='张三')

1.1.4. 可变参数args

1.1.4.1. 可变参数args

● 可变参数需要添加*,用于传递任意数量的位置参数

● 这里的args代指arguments,可以写其他任意名称

● 可变参数的本质是 将传递的参数包装成了元组

python 复制代码
def sum(*args):# 形参能够接收任意个长度的数据
    pass
# 调用可变参数的函数
sum(10,20,30)
sum(10,20,30,40)
python 复制代码
# 实现多个参数的sum函数
# 形参能够接收任意个长度的数据 args为元组类型
# 还有其他参数时,*args要放最后
def sum(name, *args):
    result = 0
    for ele in args:
        result += ele
    return result
print(sum("sum", 1, 2, 3, 4, 5)) # 15
print(sum("sum", 1, 2, 3, 4, 5, 6, 7, 8, 9)) # 45
print(sum("sum")) # 0
1.1.4.2. 可变参数 kwargs

● 用于传递任意数量的不存在的关键字参数

● 不存在的关键字参数包装成字典

● 这里的 kwargs 代指 keywords,可以写其他任意名称

python 复制代码
# **kwargs
def person_info(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

person_info(name="Alice", age=30)  # 输出: name: Alice, age: 30
person_info(name="Bob", age=25, gender="male")  # 输出: name: Bob, age: 25, gender: male
python 复制代码
def func(a,**kwargs):
    name = kwargs['name']
    age = kwargs['age']

# 调用不存在的关键字参数函数
func(name = '张三',age = 30,a=10,score=70)
1.1.4.3. 传递元组/列表给可变参数args

可以传递元组、列表给可变参数args,需要在元组/列表前加上*进行解包操作

python 复制代码
def func(*args):
    print(args)#(10,20,30)

t = (10,20,30)
# 传递元组
func(*t)
1.1.4.4. 传递字典给可变参数kwargs

在字典的前面加上**的作用是将字典中的元素解包成一个一个的不存在的关键字参数传递给函数

python 复制代码
def func(**kwargs):
    print(kwargs)

d = {'name':'张三', 'age':40}

传递字典给可变参数kwargs

func(**d)

1.1.4.5. 组合使用

**kwargs 形参可以与 *args 形参组合使用(*args 必须在 **kwargs 前面), *args 形参接收一个元组。

python 复制代码
def naixue_shop(kind, *arguments, **keywords):
    print("-- 老板,给我来杯", kind, "!")
    print("-- 没问题,我们的 %s 是全世界最好喝的!" % kind)
    for arg in arguments:
        print(arg)
    print("-" * 30)
    for kw in keywords:
        print(kw, ":", keywords[kw])

naixue_shop(
    "好喝到爆的草莓奶茶",
    "加糖", "少冰", "加奶", "加珍珠",
    price="20元", address="深圳市宝安区",
    phone="0755-11111111"
)

1.2. 递归函数

● 递归指的是把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解

● 如果一个函数在 内部调用其本身 ,这个函数就是 递归函数

● 递归的好处是:只需少量的程序就可描述出解题过程所需要的多次重复计算

python 复制代码
def factorial(n):
    # 基本情况:0 或 1 的阶乘是 1
    if n == 0 or n == 1:
        return 1
    # 递归情况:n 的阶乘是 n 乘以 (n-1) 的阶乘
    else:
        return n * factorial(n - 1)

# 示例用法
number = 5
print(f"{number} 的阶乘是: {factorial(number)}")

1.3. 作用域与闭包

1.3.1. 作用域

1.3.1.1. 局部作用域

● 在函数内部定义的变量属于局部作用域

● 这些变量只能在函数内部访问,函数外部无法访问

● 当函数执行结束后,局部变量会被销毁

python 复制代码
def my_function():
    x = 10  # x 是局部变量
    print(x)

my_function()  # 输出 10
print(x)  # 报错:NameError,x 未定义
1.3.1.2. 嵌套作用域

● 在嵌套函数中,外层函数的变量对内层函数是可见的

● 内层函数可以访问外层函数的变量,但不能直接修改(除非使用 nonlocal 关键字)

python 复制代码
def outer():
    y = 20  # y 是外层函数的局部变量
    def inner():
        print(y)  # 内层函数可以访问外层函数的变量
    inner()

outer()  # 输出 20
1.3.1.3. 全局作用域

● 在函数外部定义的变量属于全局作用域

● 全局变量在整个程序中都可以访问

● 如果需要在函数内部修改全局变量,需要使用 global 关键字

python 复制代码
z = 30  # z 是全局变量

def my_function():
    global z
    z = 40  # 修改全局变量
    print(z)

my_function()  # 输出 40
print(z)  # 输出 40
1.3.1.4. 内置作用域

● 内置作用域包含 Python 内置的函数和变量(如 print、len 等)

● 这些变量在任何地方都可以访问

python 复制代码
print(len("hello"))  # len 是内置函数

1.3.2. 闭包

闭包是指在一个函数内部定义了另一个函数,并且内层函数引用了外层函数的变量。即使外层函数已经执行完毕,内层函数仍然可以访问外层函数的变量

1.3.2.1. 闭包的特点
  1. 函数嵌套:闭包是一个嵌套函数
  2. 引用外部变量:内层函数引用了外层函数的变量
  3. 外层函数返回内层函数:外层函数将内层函数作为返回值
1.3.2.2. 闭包的示例

outer_function 是外层函数,它接收一个参数 msg

inner_function 是内层函数,它引用了外层函数的变量 msg

● 即使 outer_function 执行完毕,my_func 仍然可以访问 msg,这就是闭包的作用

python 复制代码
def outer_function(msg):
    def inner_function():
        print(msg)  # 内层函数引用了外层函数的变量 msg
    return inner_function  # 返回内层函数

my_func = outer_function("Hello, World!")
my_func()  # 输出 "Hello, World!"
1.3.2.3. 闭包的应用场景
  1. 保存状态:闭包可以用于保存函数的状态
  2. 延迟执行:闭包可以用于延迟执行某些操作
  3. 装饰器:Python中的装饰器就是基于闭包实现的
python 复制代码
def counter():
    count = 0
    def increment():
        nonlocal count  # 使用 nonlocal 修改外层函数的变量
        count += 1
        return count
    return increment

	my_counter = counter()
	print(my_counter())  # 输出 1
	print(my_counter())  # 输出 2
	print(my_counter())  # 输出 3
python 复制代码
'''
delayed_execution 函数接受一个函数 func 和一些参数 args,
然后返回一个闭包 execute,该闭包在被调用时才会执行传入的函数
add 函数的执行被延迟到了 delayed_add 被调用的时候
'''
def delayed_execution(func, *args):
    def execute():
        return func(*args)
    return execute

# 定义一个简单的函数,用于测试延迟执行
def add(a, b):
    return a + b

# 创建一个延迟执行的闭包
delayed_add = delayed_execution(add, 5, 3)

# 调用执行闭包
print(delayed_add())  # 输出 8

1.3.3. 作用域链

当访问一个变量时,Python 会按照以下顺序查找:

  1. 局部作用域:当前函数的局部变量
  2. 嵌套作用域:外层函数的变量
  3. 全局作用域:全局变量
  4. 内置作用域:Python 内置的变量

如果找不到变量,Python 会抛出 NameError 异常

1.4. Lambda表达式与高阶函数

1.4.1. Lambda表达式

Lambda表达式是一种匿名函数,它允许你在不定义完整函数的情况下快速定义一个简单的函数

Lambda表达式通常用于需要一个函数作为参数的场景。

lambda 参数: 表达式

python 复制代码
# 定义一个Lambda表达式,计算两个数的和
add = lambda x, y: x + y

# 使用Lambda表达式
result = add(3, 5)
# 输出: 8
print(result)

1.4.2. 高阶函数

高阶函数是指能够接受函数作为参数,或者返回一个函数作为结果的函数。
map函数: 对一个可迭代对象(如列表)中的每个元素应用一个函数,并返回一个包含这些函数应用结果的新迭代对象;
filter函数: 构造一个迭代器,从一个可迭代对象中筛选出所有使指定函数返回值为True的元素。

python 复制代码
# 使用Lambda表达式和高阶函数
numbers = [1, 2, 3, 4, 5]

# 使用map和Lambda表达式计算平方
squared = map(lambda x: x ** 2, numbers)
print(list(squared))  # 输出: [1, 4, 9, 16, 25]

# 使用filter和Lambda表达式过滤偶数
even_numbers = filter(lambda x: x % 2 == 0, numbers)
print(list(even_numbers))  # 输出: [2, 4]

2. 模块化编程

2.1. 模块与包管理

2.1.1. 模块module

● 模块就是一个.py文件,模块中可以定义函数,变量,类

● 模块可以被其他模块引用

2.1.1.1. 创建模块文件

● 创建文件:utils.py

python 复制代码
# 定义变量 
name = '张三'

# 定义函数
def sum(a,b):
    return a+b

# 定义类
class Person:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def __str__(self):
        return 'name:{},age:{}'.format(self.name,self.age)
2.1.1.2. 导入模块中的功能
  • 整体导入模块
python 复制代码
# 导入模块
import utils
# 使用模块中功能
print(utils.name)
# 调用模块中的sum方法
result = utils.sum(10,20)
# 创建模块utils中的Person类对象
p = utils.Person('张三',37)
  • 导入模块中部分功能
python 复制代码
# 从模块中导入部分功能
from utils import name, sum
# 使用name
print(name)
# 调用sum函数
result = sum(10,20)
  • 导入模块中全部功能
    from utils import *
python 复制代码
# 使用name
print(name)
# 调用sum函数
result = sum(10,20)
# 创建Person对象
p = Person('张三',37)

2.1.2. 模块的导入冲突

如果两个模块中有同名的变量、函数或者类,同时引入就可能出现冲突。

python 复制代码
name = "hello"
def say():
    print("hello world")
class Nice:
    pass
python 复制代码
name = "hi"
def say():
    print("hi world")
class Nice:
    pass
  • 部分导入冲突
python 复制代码
#同时引入name的话,输出的name是hi中的name,是有顺序的
from hello import name
from hi import name

print(name)
python 复制代码
#可以通过as 给功能起别名
from hello import name as hello_name
from hi import name as hi_name

print(hello_name)
print(hi_name)
  • 全部导入冲突
python 复制代码
from hello import *
from hi import *

print(name)
python 复制代码
#直接引入模块
import hello
import hi

print(hello.name)
print(hi.name)

2.1.3. 模块的内置变量

__name__是模块中的内置变量,每个模块都有这个属性

创建hello.py

python 复制代码
print(__name__)

直接运行hello.py,结果为:

python 复制代码
__main__

其它模块导入hello.py

python 复制代码
import hello

结果为:

python 复制代码
hello
2.1.3.1. __name__的特点

● 如果将当前模块作为启动项,__name__值为main

● 如果当前模块当作依赖引入,__name__值不为main,为依赖的模块名称

2.1.3.1. __name__的作用

python没有入口函数的概念,可以通过name的功能

python 复制代码
#if __name__ == '__main__': 是 Python 中的一个常见用法,用于判断当前模块是否作为主程序运行。如果是主程序,则执行下面的代码块。

def sum(m,n):
    return m+n

if __name__ == '__main__':
    a = 10
    b = 20
    result = sum(a,b)
    print(result)

2.1.4. 包package

● 包就是个文件夹,用来放模块的,限定了模块的命名空间

● 通过包把类似功能的模块进行分类,让业务更加清晰

● 在文件夹下创建__init__.py文件(空文件)

  • 引入包中模块的功能方法一

import 包名.模块名

python 复制代码
import pkg.hello

#访问模块中的属性
print(pkg.hello.name)

#访问模块中的函数
pkg.hello.say()

#访问模块中的类
nice = pkg.hello.Nice()
  • 引入包中模块的功能方法二(推荐)

from 包名 import 模块名

python 复制代码
from pkg import hello

#访问模块中的属性
print(hello.name)

#访问模块中的函数
hello.say()

#访问模块中的类
nice = hello.Nice()
  • 引入包中模块的功能方法三(推荐)

from 包名.模块名 import 变量,函数,类

python 复制代码
from pkg.hello import name
from pkg.hello import say
from pkg.hello import Nice

#访问模块中的属性
print(name)

#访问模块中的函数
say()

#访问模块中的类
nice = Nice()
  • 引入包中模块的功能方法四

from 包名.模块名 import *

python 复制代码
from pkg.hello import *

#访问模块中的属性
print(name)

#访问模块中的函数
say()

#访问模块中的类
nice = Nice()

2.2. 常用标准库

2.2.1. sys模块

sys.argv 获得启动时的参数

sys.path 获取加载的环境

sys.exit() 程序退出

2.2.2. time模块

time.time() 获取当前时间戳,单位是秒,(相对于1970年1月1日的0点0时0分0秒)

python 复制代码
import time
result = time.time() # 获取当前时间
print(result)

time.sleep(秒) 阻断程序

python 复制代码
import time

# print('程序开始')
# 睡眠3秒钟
time.sleep(3)
# print('程序结束')

2.2.3. datetime模块

datetime.datetime.now().year

datetime.datetime.now().month

datetime.datetime.now().day

python 复制代码
import datetime
# 获取当前年
year = datetime.datetime.now().year
# 获取月
month = datetime.datetime.now().month
# 获取日期
day = datetime.datetime.now().day
print(year)
print(month)
print(day)

# 格式化日期时间
now = datetime.datetime.now()
str_time = datetime.datetime.strftime(now, "%Y-%m-%d %H:%M:%S")

2.2.4. 计算排序

python 复制代码
aaa = [2, 4, 1, 2, 3, 6]
# 列表最大值
print(max(aaa))
# 列表最小值
print(min(aaa))
# 列表和
print(sum(aaa))
# 列表长度
print(len(aaa))
# 列表排序
print(sorted(aaa))
# 列表倒序
print(sorted(aaa, reverse=True))

2.2.5. math模块

math.pow 求幂

math.floor 取下

math.ceil 取上

round 四舍五入

math.sin cos tan...

python 复制代码
import math
# 幂
print(math.pow(10, 2))
# 向下取整
print(math.floor(1.8234234234234))
# 向上取整
print(math.ceil(1.1234234234234))
# 四舍五入
print(round(1.6234234234234))

# sin  传入弧度值  pi 3.14 180度
print(math.sin(1.57))

2.2.6. random模块

random.randint(start,end) # 随机整数,[start,end]

random.random() # 随机浮点数, [0,1)

random.uniform(start,end) # 随机浮点数, [start,end]

random.choice([]) # 随机列表, 返回单个元素

random.choices([]) # 随机列表, 返回列表

python 复制代码
import random

# 随机整数
print(random.randint(10, 20))
# 随机小数 [0, 1)
print(random.random())
# 随机浮点类型数据
print(random.uniform(1.3, 8.5))

# 从列表中随机获取元素
lst = [10,20,30]
print(random.choice(lst))

# 随机返回列表 返回单个元素的列表
print(random.choices(lst))

3. 学生成绩管理系统

bash 复制代码
任务描述:
编写一个简单的学生成绩管理系统。系统需要实现以下功能:
	1. 添加学生成绩:用户可以输入学生的姓名和成绩,系统将学生信息保存到一个列表中
	2. 查看所有学生成绩:系统可以显示所有学生的姓名和成绩
	3. 计算平均成绩:系统可以计算所有学生的平均成绩
	4. 查找学生成绩:用户可以通过学生姓名查找该学生的成绩
要求:
	1. 使用函数来实现每个功能
	2. 将不同的功能模块化,放在不同的函数中
	3. 使用主程序来调用这些函数,实现交互式操作
python 复制代码
# 定义一个全局列表来存储学生信息
students = []

# 1. 添加学生成绩
def add_student():
    name = input("请输入学生姓名: ")
    score = float(input("请输入学生成绩: "))
    students.append({"name": name, "score": score})
    print(f"学生 {name} 的成绩已添加。")

# 2. 查看所有学生成绩
def view_students():
    if not students:
        print("没有学生信息。")
    else:
        print("所有学生成绩如下:")
        for student in students:
            print(f"姓名: {student['name']}, 成绩: {student['score']}")

# 3. 计算平均成绩
def calculate_average():
    if not students:
        print("没有学生信息,无法计算平均成绩。")
    else:
        total = sum(student['score'] for student in students)
        average = total / len(students)
        print(f"所有学生的平均成绩为: {average:.2f}")

# 4. 查找学生成绩
def find_student():
    name = input("请输入要查找的学生姓名: ")
    for student in students:
        if student['name'] == name:
            print(f"学生 {name} 的成绩为: {student['score']}")
            return
    print(f"未找到学生 {name} 的成绩。")

# 主程序
def main():
    while True:
        print("\n学生成绩管理系统")
        print("1. 添加学生成绩")
        print("2. 查看所有学生成绩")
        print("3. 计算平均成绩")
        print("4. 查找学生成绩")
        print("5. 退出系统")

        choice = input("请选择操作 (1/2/3/4/5): ")

        if choice == '1':
            add_student()
        elif choice == '2':
            view_students()
        elif choice == '3':
            calculate_average()
        elif choice == '4':
            find_student()
        elif choice == '5':
            print("退出系统。")
            break
        else:
            print("无效的选择,请重新输入。")

# 运行主程序
if __name__ == "__main__":
    main()

以上,欢迎有从事同行业的电子信息工程、互联网通信、嵌入式开发的朋友共同探讨与提问,我可以提供实战演示或模板库。希望内容能够对你产生帮助!

相关推荐
计算机安禾4 小时前
【c++面向对象编程】第38篇:设计原则(二):里氏替换、接口隔离与依赖倒置
开发语言·c++
feifeigo1234 小时前
STM32矩阵键盘驱动(库函数版)实现
stm32·矩阵·计算机外设
_院长大人_4 小时前
Java Excel导出:如何实现自定义表头与字段顺序的完全控制
java·开发语言·后端·excel
code_whiter4 小时前
C++1进阶(继承)
开发语言·c++
来恩10034 小时前
JSTL的标签库种类
java·开发语言
Miss_min4 小时前
128K长序列数据生成
开发语言·python·深度学习
love530love4 小时前
MingLi-Bench 项目部署实录:基于 EPGF 架构的工程化实践
人工智能·windows·python·架构·aigc·epgf·mingli-bench
小宋0014 小时前
QT中控件qss样式修改
开发语言·qt
图像僧5 小时前
vs2019中的属性页使用说明
java·开发语言·jvm