本篇技术博文摘要 🌟
本文系统梳理了Python函数的核心知识点,从基础概念到高级特性,构建了完整的函数编程知识体系。内容涵盖:变量作用域的局部与全局划分、函数注释的规范写法、参数传递中值与引用的区别、匿名函数的灵活应用,以及Python 3.8的新特性(如海象运算符)。进一步深入偏函数、嵌套函数与闭包的实现,详解装饰器的语法与进阶用法(参数传递、多装饰器顺序、返回值处理)。最后结合高阶函数(
map
、filter
、reduce
)实现数据批量操作,并通过综合实验——工资计算系统,串联知识点,实践员工信息管理与月薪计算逻辑。
引言 📘
- 在这个变幻莫测、快速发展的技术时代,与时俱进是每个IT工程师的必修课。
- 我是盛透侧视攻城狮,一名什么都会一丢丢的网络安全工程师,也是众多技术社区的活跃成员以及多家大厂官方认可人员,希望能够与各位在此共同成长。
上节回顾
目录
本篇技术博文摘要 🌟
引言 📘
上节回顾
01-函数中变量的作用域
02-函数注释
03-值传递引用传递
04-Py函数以及匿名函数
05-python3.8新特性
06-偏函数
07-函数的嵌套
08-闭包
09-装饰器
10-装饰器参数
11-一个函数被多个装饰器装饰
12-装饰器函数返回值问题
13-高阶函数map.py
14-filter函数
15-reduce函数
综合实验:设计一个工资计算系统,录入员工信息,计算员工的月薪
欢迎各位彦祖与热巴畅游本人专栏与技术博客
你的三连是我最大的动力
点击➡️指向的专栏名即可闪现
01-函数中变量的作用域
- 原理:Python变量作用域分为局部作用域(函数内部)和全局作用域(函数外部)。
- 作用:理解变量可见性和生命周期
a = 100def test_01():a = 10b = 20print(a)print(b)def test_02():print(a)def test_03():global aa += 100print(a)test_03()
# test_02()
# test_01()
# print(b)'''
全局变量:声明在函数外部的变量称为全局变量'''
- 函数内部可以使用全局变量,但是不能修改,如果一定要在函数内部修改全局变量,那么global
02-函数注释
- 原理:使用文档字符串(
"""..."""
)和类型注解(Python 3.5+)为函数添加说明。- 作用:提高代码可读性,IDE可识别提示
def add(a: int, b: int) -> int:"""返回两个整数的和"""return a + b
print(add.__doc__) # 输出:返回两个整数的和
03-值传递引用传递
- 原理:
- 值传递:在传递参数的时候,仅仅是将自己的值拷贝了一份,传递给了函数的参数,变量不会改变
- 引用传递:在传递参数时,传地址,函数形参获取的值也是同一块内存
- 作用:理解参数修改对原数据的影响
def test_01(x, y):x += 10y += 100print(x)print(y)a = 10
b = 20
test_01(a, b)
print(a)
print(b)def test_02(nums):print(id(nums))nums.append(10)nums.append(100)print(nums)list1 = [1, 2, 3]
print(id(list1))
test_02(list1)
print(list1)
04-Py函数以及匿名函数
- 原理:
-
lambda [arg1,arg2……]: 代码块(函数体)
-
存在函数作为参数传递给函数,并且又不想让外界访问,而且参数函数足够简单,即可以定义为匿名函数(lambda表达式)
-
- 作用:简化代码,常用于高阶函数参数
def now():print("1111111111")f = now
a = f
# __name__,拿到函数的名字
print(f.__name__)
print(a.__name__)
def test_func(add):result = add(1, 2)print(result)def compute(a,b):return a+btest_func(compute)test_func(lambda a, b: a + b)
- function(){}
- 在python中,将一个函数作为参数传到另一个函数中去
- 函数的参数数据类型:只要是一个对象就可以
- 函数本身就是一个对象
05-python3.8新特性
- 原理:Python 3.8引入海象运算符(
:=
)、位置参数限定符(/
)等。- 作用:提升代码简洁性和灵活性
# 海象运算符
if (n := len([1,2,3])) > 2:print(f"长度是{n}") # 输出:长度是3# 位置参数
def func(a, b, /, c):print(a, b, c)
func(1, 2, c=3) # 正确
func(a=1, b=2, c=3) # 报错:a,b必须位置参数
# 声明函数参数类型
# def 函数名(a,b)def add(x: int, y: int) -> int:return x + yprint(add(1, 2))
print(add("a", "b"))
06-偏函数
- 原理:使用
functools.partial
固定函数的部分参数,生成新函数。- 作用:简化参数传递。
from functools import partial
def power(base, exp):return base ** expsquare = partial(power, exp=2)
print(square(5)) # 输出25
# functools模块提供很多方法,其中有一个就是偏函数# int(3.14)# def int2(x, base=2):
# return int(x, base)
#
# print(int2("10010",10))import functoolsint2 = functools.partial(int, base=2)print(int2("100101"))
07-函数的嵌套
- 原理:在函数内部定义另一个函数。
- 作用:封装逻辑,限制函数作用域。
def outer():def inner():print("内部函数")inner()outer() # 输出:内部函数
def fun1():b = 20def fun2(): #fun2=def(){}print(b)return fun2a = fun1()
a()
a()
a()
- 综上所述:
- 1、函数可以作为返回值进行返回
- 2、函数可以作为参数进行传进
- 3、函数名本质上是一个变量名,指向函数的内存地址
08-闭包
- 原理:一个函数嵌套一个函数,内层函数用到外层函数的局部变量,内层函数就被称为闭包
- 作用:保留状态,实现数据隐藏。
def counter():count = 0def increment():nonlocal countcount += 1return countreturn incrementc = counter()
print(c(), c()) # 输出1, 2
def outer():a = 1def inner():#内层函数如果要改变外层函数局部变量的值,需要使用nonlocal关键字赋予权限nonlocal aa += 1inner()print(a)return innerouter()# 可以让一个变量常驻在内存当中
# 可以避免全局变量被修改
09-装饰器
- 原理:装饰器本质上是一个闭包,作用是不改变原有函数的前提下,为函数添加新的功能,但是源代码不改变
-
雏形: def wrapper(目标函数):def inner():之前添加的功能目标函数()之后添加的功能return inner
- 作用:无侵入式增强功能(如用户登录、日志、计时)
10-装饰器参数
- 原理:装饰器本身支持参数传递。
- 作用:动态配置装饰器行为。
def guanjia(fn):# 定义一个名为guanjia的装饰器函数,它接受一个函数作为参数print("这波传入的函数是", fn.__name__)# 打印传入函数的名称,方便调试和理解装饰器的工作过程def inner(*args, **kwargs):# 定义一个内部函数inner,它使用了可变参数*args和**kwargs# *args用于接收任意数量的位置参数,**kwargs用于接收任意数量的关键字参数print("开挂")# 在调用被装饰的函数之前,打印“开挂”信息fn(*args, **kwargs)# 调用被装饰的函数,并将接收到的参数传递给它print("关闭外挂")# 在调用被装饰的函数之后,打印“关闭外挂”信息return inner# 返回内部函数inner,这样当使用@guanjia语法时,实际上是将被装饰的函数替换为inner函数@guanjia # play_wz = guanjia(play_wz)
# 使用@guanjia语法将guanjia装饰器应用到play_wz函数上
# 这相当于执行了play_wz = guanjia(play_wz),将play_wz函数替换为guanjia返回的inner函数
def play_wz(uname, password):# 定义一个名为play_wz的函数,它接受两个参数:用户名和密码print("来和妲己玩耍吧")# 打印游戏相关的提示信息print(f"用户名{uname},密码是{password}")# 打印用户名和密码信息@guanjia
# 使用@guanjia语法将guanjia装饰器应用到play_dnf函数上
def play_dnf(uname, pwd, g):# 定义一个名为play_dnf的函数,它接受三个参数:用户名、密码和技能print("你好啊,我是赛利亚,今天又是美好的一天")# 打印游戏相关的提示信息print(f"用户名{uname},密码是{pwd},技能是{g}")# 打印用户名、密码和技能信息play_wz("zhangsan", "123456")
# 调用被装饰后的play_wz函数,传入用户名和密码
# 实际执行的是inner函数,会先打印“开挂”,然后调用原始的play_wz函数,最后打印“关闭外挂”play_dnf("lisi", "lisisi", "吹")
# 调用被装饰后的play_dnf函数,传入用户名、密码和技能
# 同样会先打印“开挂”,然后调用原始的play_dnf函数,最后打印“关闭外挂”
- 装饰器:
guanjia
是一个装饰器函数,它可以在不修改原函数代码的情况下,为原函数添加额外的功能(如打印 “开挂” 和 “关闭外挂” 信息)。- 可变参数:
inner
函数使用了*args
和**kwargs
可变参数,这样可以处理任意数量和类型的参数,使得装饰器可以应用到不同参数的函数上。- 函数调用:调用被装饰后的函数时,实际上是调用了
inner
函数,inner
函数会在调用原函数前后执行额外的操作。
11-一个函数被多个装饰器装饰
- 原理:装饰器按从下到上的顺序执行
# 定义装饰器函数 wrapper1,它接收一个函数作为参数
def wrapper1(fn):# 定义内部函数 inner,用于包装被装饰的函数def inner(*args, **kwargs):# 在调用被装饰函数之前,打印特定信息print("11111111111111111")# 调用被装饰的函数,并传入参数fn(*args, **kwargs)# 在调用被装饰函数之后,打印特定信息print("111111111111111111")# 返回内部函数 innerreturn inner# 定义装饰器函数 wrapper2,它接收一个函数作为参数
def wrapper2(fn):# 定义内部函数 inner,用于包装被装饰的函数def inner(*args, **kwargs):# 在调用被装饰函数之前,打印特定信息print("2222222222222222")# 调用被装饰的函数,并传入参数fn(*args, **kwargs)# 在调用被装饰函数之后,打印特定信息print("222222222222222222")# 返回内部函数 innerreturn inner# 使用 wrapper1 装饰 wrapper2 装饰后的 target 函数
# 首先执行 @wrapper2,将 target 函数替换为 wrapper2.inner
# 然后执行 @wrapper1,将 wrapper2.inner 作为参数传入 wrapper1,得到 wrapper1.inner
@wrapper1
@wrapper2
# 定义目标函数 target
def target():# 打印函数内的信息print("我是函数")# 调用被装饰后的 target 函数,实际上调用的是 wrapper1.inner
target()# 以下是使用 time 模块的代码
# 导入 time 模块,该模块提供了各种与时间相关的函数
import time
# 打印当前的时间戳,即从 1970 年 1 月 1 日午夜(UTC)开始到现在的秒数
print(time.time())
# 让程序暂停执行 2 秒
time.sleep(2)
12-装饰器函数返回值问题
- 装饰器
guanjia
:在调用被装饰的函数前后分别打印提示信息,并返回被装饰函数的返回值
# 定义一个名为guanjia的装饰器函数,它接收一个函数作为参数
def guanjia(fn):# 定义内部函数inner,用于包裹被装饰的函数def inner(*args, **kwargs):# 在调用被装饰函数前打印提示信息print("11111111111111111")# 调用被装饰的函数,并将其返回值赋给变量retret = fn(*args, **kwargs)# 在调用被装饰函数后打印提示信息print("111111111111111111")# 返回被装饰函数的返回值return ret# 返回内部函数innerreturn inner# 定义一个名为rizhi的装饰器函数,它接收一个函数作为参数
def rizhi(fn):# 定义内部函数inner,用于包裹被装饰的函数def inner(*args, **kwargs):# 在调用被装饰函数前打印日志信息print("玩了一次游戏")# 调用被装饰的函数fn(*args, **kwargs)# 返回内部函数innerreturn inner# 使用guanjia装饰器装饰play_wz函数
# 相当于执行了play_wz = guanjia(play_wz)
@guanjia
# 定义一个名为play_wz的函数,接收用户名和密码作为参数
def play_wz(uname, password):# 打印用户名和密码信息print(f"用户名是{uname},密码是{password}")# 打印游戏相关提示信息print("来和妲己玩耍吧")# 返回游戏相关的字符串return "妲己玩的很666"# 调用被装饰后的play_wz函数,并将返回值赋给变量a
a = play_wz('gouxin', 123456)
# 打印变量a的值
print(a)# 使用rizhi装饰器装饰yonghu函数
# 相当于执行了yonghu = rizhi(yonghu)
@rizhi
# 定义一个名为yonghu的函数,接收名字和密码作为参数
def yonghu(name, pwd):# 打印名字和密码信息print(f"名字为{name},密码是{pwd}")# 打印相关提示信息print("ljs帅到飞起")# 返回一个字符串return "蔡志恒我直接爱思了"# 调用被装饰后的yonghu函数,并将返回值赋给变量b
b = yonghu('caizhiheng', 6666)
# 打印变量b的值
print(b)
13-高阶函数map.py
- 原理:从可迭代对象中获取第一个元素,作为函数的参数,传入函数中,将函数执行后返回结果作为生成对象中的第一个元素,最终返回一个可迭代对象
- 语法:
map(将来可以调用的,可迭代数据)
# map()
a = map(lambda x: x * x, [1, 2, 3]) # [1,4,9]
print(list(a))
for i in a:print(i)# map(将来可以调用的,可迭代数据)''''''# b = map(lambda x,y:x+y,[1,2,3],[4,5,6])
# for i in b:
# print(i)def f1(x, y):return x, yl1 = [0, 1, 2, 3, 4, 5, 6]
l2 = ['sun', 'm', 't', 'w', 't', 'f', 's']l3 = map(f1, l1, l2)
print(list(l3))
- 第一个
map
示例:使用lambda
函数对列表[1, 2, 3]
中的元素进行平方操作,将map
返回的迭代器转换为列表打印后,迭代器变空,后续遍历无输出。- 注释掉的
map
示例:展示了map
处理两个可迭代对象的情况,使用lambda
函数对两个列表对应位置元素相加。- 自定义函数
f1
与map
:定义函数f1
接受两个参数并返回元组,使用map
将f1
应用到l1
和l2
对应元素上,最后将结果迭代器转换为列表打印。
14-filter函数
- 原理:filter(func, iterable) 过滤满足条件的元素,返回迭代器。
# filter() 过滤对指定的序列执行过滤a = filter(lambda x: x % 2, [1, 2, 3, 4])
print(list(a))
# 只要成立(为真:0为假,其余数字为真),就保留
15-reduce函数
- 原理:用上一次计算的结果作为下一次传入的x值,如果上一次没有计算结果,则将可迭代数据的强两个元素分别作为x,y传入,如果有额外数据,会作为第一次传入的x值
from functools import reducea = reduce(lambda x, y: x + y, [1, 2, 7, 4],5)
print(a)
综合实验:设计一个工资计算系统,录入员工信息,计算员工的月薪
# 设计一个工资计算系统,录入员工信息,计算员工的月薪
from abc import ABCMeta, abstractmethodclass Employee(metaclass=ABCMeta): # 抽象类不能实例化,但是子类可以继承# 继承抽象类def __init__(self, name):self.name = name# 将这个方法变成抽象方法,对象不能直接调用,但是子类可以重写这个方法@abstractmethoddef give_salary(self):passclass Magnaer(Employee):# 创建一个部门经理类,部门经理每月固定月薪666666666666666.00元def give_salary(self):return 666666666666666.00class Programmer(Employee):# 创建一个程序员类,添加一个工作时间属性为 程序员计时支付月薪,每小时2元# super().__init__() 就是调用父类的init方法, 同样可以使用super()去调用父类的其他方法。def __init__(self, name, work_hour=0):super(Programmer, self).__init__(name)self.work_hour = work_hourdef give_salary(self):return self.work_hour * 2class SalesMan(Employee):# 创建一个销售员类,添加一个销售员按照1元底薪加上销售额5%的提成支付月薪的销售属性def __init__(self, name, sales=0):super(SalesMan, self).__init__(name)self.sales = salesdef give_salary(self):return self.sales * 0.05 + 1if __name__ == '__main__':Salary = [Magnaer('任正非'), Programmer('马化腾'), Programmer('雷军'), Programmer('埃隆·马斯克'), SalesMan('马云'),SalesMan('蒂姆库克')]for i in Salary:if isinstance(i, Programmer):i.work_hour = float(input(f'请输入{i.name}工作时长:'))elif isinstance(i, SalesMan):i.sales = float(input(f'请输入{i.name}的销售额:'))print(f'{i.name}的本月月薪为¥{i.give_salary()} ')
欢迎各位彦祖与热巴畅游本人专栏与技术博客
你的三连是我最大的动力
点击➡️指向的专栏名即可闪现
➡️渗透终极之红队攻击行动
➡️动画可视化数据结构与算法
➡️ 永恒之心蓝队联纵合横防御
➡️华为高级网络工程师
➡️华为高级防火墙防御集成部署
➡️ 未授权访问漏洞横向渗透利用
➡️逆向软件破解工程
➡️MYSQL REDIS 进阶实操
➡️红帽高级工程师
➡️红帽系统管理员
➡️HVV 全国各地面试题汇总