第六章 函数进阶
1. 从头认识函数
之前Python之函数入门已经对函数有了初步的介绍,此章我们探讨函数的高阶部分。
# 1.函数也是对象
x1 = 999# int类的实例对象
x2 = 'Python'# str类的实例对象
x3 = [11, 22, 33] # list类的实例对象
defmessage():# message函数是function类的实例对象
print('Python')
print(type(x1)) # <class 'int'>
print(type(x2)) # <class 'str'>
print(type(x3)) # <class 'list'>
print(type(message())) # <class 'function'>
# 2.函数可以动态添加属性
defmessage():
print('Python')
message.desc = '这是一个Python信息'
message.version = 1.0
print(message.desc) # 这是一个Python信息
print(message.version) # 1.0
# 3.函数可以赋值给变量
defmessage():
print('Python')
message.desc = 'Hello Python'
message.version = 1.0
say_hello = message
say_hello() # Python
print(say_hello.desc) # Hello Python
print(say_hello.version) # 1.0
# 4.可变参数 vs 不可变参数
# 不可变参数
a = 666
defwelcome(data):
print('data修改前:', data, '对象地址:', id(data))
data = 888
print('data修改后:', data, '对象地址:', id(data))
print('函数调用前:', a, '对象地址:', id(a))
welcome(a)
print('函数调用后:', a, '对象地址:', id(a))
# 执行结果顺序:
# 函数调用前: 666 对象地址: 1532474442064
# data修改前: 666 对象地址: 1532474442064
# data修改后: 888 对象地址: 1532474442032
# 函数调用后: 666 对象地址: 1532474442064
# 可变参数
a = [10, 20, 30]
defwelcome(data):
print('data修改前:', data, '对象地址:', id(data))
data[2] = 99
print('data修改后:', data, '对象地址:', id(data))
print('函数调用前:', a, '对象地址:', id(a))
welcome(a)
print('函数调用后:', a, '对象地址:', id(a))
# 执行结果顺序:
# 函数调用前: [10, 20, 30] 对象地址: 1532472185216
# data修改前: [10, 20, 30] 对象地址: 1532472185216
# data修改后: [10, 20, 99] 对象地址: 1532472185216
# 函数调用后: [10, 20, 99] 对象地址: 1532472185216
# 5.函数也可以作为参数
defmessage():
print("Hello Python")
defcall(fun):
print("call函数被调用了")
fun()
call(message)
# 执行结果:
# call函数被调用了
# Hello Python
# 6.函数也可以作为返回值
defmessage():
print("Hello")
defview_msg(msg):
print(msg)
return view_msg
result = message()
result("Python")
message()('Python')
# 执行结果:
# Hello
# Python
# Hello
# Python
2. 函数的多返回值
在return关键字后面写多个值,并且多个值之间用逗号隔开,Python会自动把多个值打包成一个元组。
# 一.函数的多返回值
defcalculate(num1, num2):
result1 = num1 + num2
result2 = num1 - num2
return result1, result2
result = calculate(10, 5)
print(result) # (15, 5)
res1, res2 = calculate(10, 5)
print(res1, res2) # 15 5
3. 参数的打包与解包
定义函数时,打包接收参数:
**形参名:打包所有的位置参数(会形成一个字典)。
调用函数时,解包传递参数:
**变量名:将字典拆解成一个一个key = value形式的关键字参数。
# 二.参数的打包和解包
# 1.打包接收参数:
# *args :打包所有的位置参数(会形成一个元组)
# **kwargs :打包所有的关键字参数(会形成一个字典)
defview_info(*args, **kwargs):
print(args) # (10, 20, 30)
print(kwargs) # {'name': '张三丰', 'age': 99, 'gender': '神仙'}
view_info(10, 20, 30, name='张三丰', age=99, gender='神仙')
# 2.解包传递参数
# *变量名 :将元组拆解成一个一个独立的位置参数
# **变量名 :将字典拆解一个一个 key=value 形式的关键字参数
defshow_info(num1, num2, num3, name, age, gender):
print(num1, num2, num3) # 10 20 30
print(name, age, gender) # 张三丰 99 神仙
nums = (10, 20, 30)
person = {'name':'张三丰', 'age':99, 'gender':'神仙'}
show_info(*nums, **person)
# 3.打包接收参数和解包传递参数一起使用
defshow_info(*args, **kwargs):
print(args) # (10, 20, 30)
print(kwargs) # {'name': '张三丰', 'age': 99, 'gender': '神仙'}
nums = (10, 20, 30)
person = {'name':'张三丰', 'age':99, 'gender':'神仙'}
show_info(*nums, **person)
4. 高阶函数
当一个函数的参数是函数或者返回值是函数,那么该函数就是高阶函数。
# 高阶函数:当一个函数的『参数是函数』或者『返回值是函数』那该函数就是『高阶函数』。
# 高阶函数的意义:
# 1.代码的复用性高:可以把行为“独立出去”,传入不同函数实现不同的逻辑。
# 2.能让函数更灵活,更通用。
# 3.高阶函数是:装饰器,闭包的基础。
definfo(msg):
return'【提示】:' + msg
defwarning(msg):
return'【警告】:' + msg
deferror(msg):
return'【错误】:' + msg
deflog(fun, text):
print(fun(text))
log(info, '文件保存成功!') # 【提示】:文件保存成功!
log(warning, '磁盘空间不足!') # 【警告】:磁盘空间不足!
log(error, '该用户不存在!') # 【错误】:该用户不存在!
5. 条件表达式
表达式:执行后最终能得到一个值的代码,就是表达式,例如一下都是表达式。
# 表达式:执行后能得到值的代码,就是表达式(表达式最终会形成一个值,可以写在任何需要值的地方)。
# a1 = 3 + 5
# a2 = 'abc' * 3
# print(5 > 3)
# int('y' in 'python')
# a5 = len('hello')
条件表达式:根据不同的条件,得到不同的值,又称:三元表达式,三目原算法。
具体规则:如果条件为真,整个表达式的结果就是结果1,否则就是结果2。
# 语法格式:
结果1if 条件 else 结果2
# 条件表达式:根据条件的真假,在两个值中二选一的表达式。(又称:三元表达式,三元运算符)。
age = 18
# 传统的if-else写法:
if age >= 18:
text = '成年'
else:
text = '未成年'
print(text) # 成年
# 条件表达式写法:值1 if 条件 else 值2
text = '成年'if age >= 18else'未成年'
print(text) # 成年
# 条件表达式的使用场景:简单的二选一场景
rain = True
eat = '外卖'if rain else'出去吃'
is_vip = False
disscount = 0.8if is_vip else1.0
is_login = False
msg = 'Hello'if is_login else'Python'
print(eat) # 外卖
print(disscount) # 1.0
print(msg) # Python
6. 匿名函数
概念:所谓匿名函数,就是没有名字的函数,它无需使用def关键字去定义。
语法:Python中使用lambda关键字来定义匿名函数,格式为:lambda 参数: 表达式。
使用场景:当一个函数只用一次,只做一点点小事,使用匿名函数会更简洁。
# 使用普通函数实现计算效果
defadd(a, b):
return a + b
defsub(a, b):
return a - b
defcalculate(fun, a, b):
print(f'计算结果为:{fun(a, b)}')
calculate(add, 6, 5) # 计算结果为:11
calculate(sub, 6, 5) # 计算结果为:1
# 匿名函数
add1 = lambda a, b: a + b
add2 = lambda a: a + a
add3 = lambda : '我是add3函数'
result1 = add1(10, 20)
result2 = add2(30)
result3 = add3()
print(result1) # 30
print(result2) # 60
print(result3) # 我是add3函数
# 使用匿名函数实现计算效果
defcalculate(fun, a, b):
print(f'计算结果为:{fun(a, b)}')
calculate(lambda a, b: a + b, 10, 20) # 计算结果为:30
calculate(lambda a, b: a - b, 10, 20) # 计算结果为:-10
匿名函数注意点:
# 匿名函数注意点:
# 1.只能写一行,不能写多行代码。
# 2.不能写代码块(if,for,while)
# 3.冒号右边必须是表达式,且只能写一个表达式。
# 4.表达式结果自动作为返回值。
is_adult = lambda age: '成年'if age >= 18else'未成年'
print(is_adult(18)) # 成年
print(is_adult(16)) # 未成年
7. 数据处理函数
7.1 map函数
map函数:对一组数据中的每一个元素,统一执行某种操作(加工),并生成一组新数据。
语法格式:map(操作函数,可迭代对象)。
# 统一数据处理
nums = [10, 20, 30, 40, 50]
# map函数的返回值是一个迭代器对象,需要我们自己去手动遍历,或者手动类型转换。
result = map(lambda x: x * 2, nums)
print(list(result)) # [20, 40, 60, 80, 100]
print(nums) # [10, 20, 30, 40, 50]
# 字符串转换
bookName = ('Python', 'java', 'vue')
result = map(lambda x: x.upper(), bookName)
print(tuple(result)) # ('PYTHON', 'JAVA', 'VUE')
print(bookName) # ('Python', 'java', 'vue')
# 类型转换
str_num = {'1', '2', '3', '4', '5', '6', '7', '8', '9'}
result = map(int, str_num)
print(set(result)) # {1, 2, 3, 4, 5, 6, 7, 8, 9}
print(str_num) # {'3', '9', '1', '4', '7', '2', '5', '8', '6'}
map函数注意点:
延迟执行:map不会立刻计算,只有在"需要结果"时才会执行计算。
返回的是迭代器对象,且一旦遍历完成,就会被"耗尽"。
nums = [10, 20, 30, 40, 50]
result = list(map(lambda x: x * 2, nums))
print(result) # [20, 40, 60, 80, 100]
print(result) # [20, 40, 60, 80, 100]
print(result) # [20, 40, 60, 80, 100]
7.2 filter函数
filter函数:从一组数据中,筛选出符合条件的元素(过滤),并组成一组新数据。
语法格式:filter(过滤函数,可迭代对象)
# 筛选数值
nums = [10, 20, 30, 40, 50]
result = filter(lambda num: num > 30, nums)
print(list(result)) # [40, 50]
print(nums) # [10, 20, 30, 40, 50]
# 筛选成年人
persons = [
{'name':'唐僧', 'age':100, 'gender':'男'},
{'name':'孙悟空', 'age':999, 'gender':'男'},
{'name':'猪八戒', 'age':888, 'gender':'男'},
{'name':'沙和尚', 'age':777, 'gender':'男'},
{'name':"白龙马", 'age':666, 'gender':'男'},
{'name':'白骨精', 'age':555, 'gender':'女'},
]
result = filter(lambda per: per['age'] >= 999, persons)
print(list(result)) # [{'name': '孙悟空', 'age': 999, 'gender': '男'}]
# 过滤一下非法字符串
names = ['唐僧', '', '猪八戒', '沙和尚', 'None']
result = filter(lambda n: n, names)
print(list(result)) # ['唐僧', '猪八戒', '沙和尚', 'None']
# filter注意点:
# 1.延迟执行:filter不会立刻筛选,只有在"需要结果"时才会执行。
# 2.返回的是迭代器对象,且一旦遍历完成就会被耗尽。
# 3.filter可能会影响元素数量。
# filter函数的特殊用法,如果不传递过滤函数,那么自动回过滤掉"假值"。
data = [0, 1, '', 'hello', [], (), 5]
result = filter(None, data)
print(list(result)) # [1, 'hello', 5]
7.3 sorted函数
sorted函数:对一组数据进行排序,返回一组新数据。
语法格式:sorted(可迭代对象, key=xxx, reverse=xxx)
# 数字排序
nums = [1, 2, 3, 4, 5, 6]
result = sorted(nums, reverse=True)
print(result) # [6, 5, 4, 3, 2, 1]
# 按照字符串的长度去排序
names = ['Sql', 'Python', 'Java', 'Vue']
result = sorted(names, key=len, reverse=True)
print(result) # ['Python', 'Java', 'Sql', 'Vue']
# 根据字典中的某个字段进行排序
persons = [
{'name':'唐僧', 'age':100, 'gender':'男'},
{'name':'孙悟空', 'age':999, 'gender':'男'},
{'name':'猪八戒', 'age':888, 'gender':'男'},
{'name':'沙和尚', 'age':777, 'gender':'男'},
{'name':"白龙马", 'age':666, 'gender':'男'},
{'name':'白骨精', 'age':555, 'gender':'女'},
]
result = sorted(persons, key=lambda p: p['age'], reverse=True)
print(result) #
# 执行结果:
# [{'name': '孙悟空', 'age': 999, 'gender': '男'},
# {'name': '猪八戒', 'age': 888, 'gender': '男'},
# {'name': '沙和尚', 'age': 777, 'gender': '男'},
# {'name': '白龙马', 'age': 666, 'gender': '男'},
# {'name': '白骨精', 'age': 555, 'gender': '女'},
# {'name': '唐僧', 'age': 100, 'gender': '男'}]
# 我们之前将的max函数,min函数,也可以传递key参数,用于设置筛选依据
result1 = max(persons, key=lambda p: p['age'])
result2 = min(persons, key=lambda p: p['age'])
print(result1) # {'name': '孙悟空', 'age': 999, 'gender': '男'}
print(result2) # {'name': '唐僧', 'age': 100, 'gender': '男'}
7.4 reduce函数
reduce函数:将一组数据不断合并,最终归并成一个结果。
语法格式:reduce(合并函数, 可迭代对象, 初始值)
备注:reduce函数需要从functools模块中引入才能使用。
# reduce函数:将一组数据不断“合并”,最终归并成一个结果。
# 语法格式:reduce(合并函数, 可迭代对象, 初始值)。
# 备注:reduce函数需要从 functools 模块中引入才能使用。
# 从functools模块中引入reduce
from functools import reduce
# 数值统计
nums = [1, 2, 3, 4, 5, 6]
result = reduce(lambda x, y: x + y, nums, 10)
print(result) # 31
# 字符串拼接
str_list = ['p', 'y', 't', 'h', 'o', 'n']
result = reduce(lambda x, y: x + y, str_list)
print(result) # python
8. 列表推导式
概念:用一条简洁的语句,从可迭代对象中,生成新猎德语法结构。
语法格式:[表达式 for 变量 in 可迭代对象]
# 列表推导式:用一条简洁语句,从可迭代对象中,生成新列表的语法结构。
# 备注:列表推导式本质上是对 for循环 + append() 的一种简写形式。
# 语法格式:[表达式 for 变量 in 可迭代对象]
# 需求:让列表中每个元素,都变为原来的2倍,得到是一个新的列表
# 方式一:用map函数
nums = [10, 20, 30, 40, 50]
result = list(map(lambda x: x * 2, nums))
print(result) # [20, 40, 60, 80, 100]
# 方式二:用for循环 + append()
nums = [10, 20, 30, 40, 50]
result = []
for n in nums:
result.append(n * 2)
print(result) # [20, 40, 60, 80, 100]
# 方式三:用列表推导式
nums = [10, 20, 30, 40, 50]
result = [n * 2for n in nums]
print(result) # [20, 40, 60, 80, 100]
# 带条件的列表推导式
nums = [10, 20, 30, 40, 50]
result = [n * 2for n in nums if n > 20]
print(result) # [60, 80, 100]
# 字典推导式
names = ['唐僧', '孙悟空', '猪八戒', '沙和尚']
scores = [10, 20, 30, 40]
result = {names[i]: scores[i] for i in range(len(names))}
print(result) # {'唐僧': 10, '孙悟空': 20, '猪八戒': 30, '沙和尚': 40}
# 集合推导式
names = ['唐僧', '孙悟空', '猪八戒', '沙和尚']
result = {n + '!'for n in names}
print(result) # {'猪八戒!', '唐僧!', '沙和尚!', '孙悟空!'}
names = ['唐僧', '孙悟空', '猪八戒', '沙和尚']
# Python中没有元组推导式,下面这种写法叫:生成器。
result = {n + '!'for n in names}
print(result) # {'猪八戒!', '唐僧!', '沙和尚!', '孙悟空!'}
9. 常用内置函数梳理
一下函数his截止目前,我们需要掌握的一些常用函数。下面的并不是所有,后面还会学习更多的内置函数。
| |
|---|
print | |
objects | |
sep | |
end | |
file | |
flush | |
input() | |
# 一、输入与输出
# print() ===> 输出指定内容
# 完整参数:print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
# 参数详解:
# 1.objects:要输出的内容
# 2.sep:分隔符
# 3.end:结束符
# 4.file:输出位置
# 5.flush:是否立即刷新
f = open('a.txt', 'w', encoding='utf-8')
print(10, 20, 30, 40, sep='-', end='!', file=f)
import time
# 第一种进度条
print('加载中', end='')
for index in range(5):
print('.', end='', flush=True)
time.sleep(1)
print('完成!', end='')
# 第二种进度条
for index in range(1, 101):
print(f'\r已加载{index}%', end='', flush=True)
time.sleep(0.1)
| |
|---|
int() | |
float() | |
str() | |
bool() | |
list() | |
tuple() | |
set() | |
dict() | |
| |
|---|
abs() | |
round() | 银行家舍入法:小于5舍,大于5入,等于5看前面数字的奇偶(奇入偶舍) |
pow(a, b) | |
pow(a, b, c) | |
divmod(a, b) | |
max() | |
min() | |
sum() | |
map() | |
filter() | |
reduce() | |
sorted() | |
# 三、数学相关
# abs() =========> 取绝对值
print(abs(-9)) # 9
print(abs(-2.5)) # 2.5
print(abs(3 - 5)) # 2
# round() =======> 四舍五入
# 注意:round函数的四舍五入,是银行家舍入法:小于5就舍,大于5就入,等于5看奇偶(奇入偶舍)
print(round(3.4)) # 3
print(round(4.6)) # 5
print(round(6.5)) # 6
print(round(7.5)) # 8
print(round(7.543, 2)) # 7.54
# pow() =========> 次方
print(pow(2, 3)) # 8 # 2的3次方
print(pow(2, -1)) # 0.5 # 2的-1次方
print(pow(2, 0.5)) # 1.4142135623730951 # 2的开平方
print(pow(2, 3, 5)) # 3 # 2的3次方对5取模
# divmod() ======> 商和余数
print(divmod(10, 3)) # (3, 1)
| |
|---|
len() | |
range() | |
enumerate() | |
zip() | |
# 四、数据容器相关
# len() ==========> 获取容器中元素的个数
# range() ========> 生成一个数字序列(可用于循环)
for index in range(0, 10, 2):
print(index)
# enumerate() ====> 给序列添加索引
# zip() ==========> 将多个序列一一配对
names = ('张三', '李四', '王五')
scores = [60, 70, 80]
result = zip(names, scores)
for item in result:
print(item)
| |
|---|
type() | |
isinstance(obj, type) | |
issubclass(A, B) | |
id() | |
# 六、逻辑判断相关
# all() ====> 全为真返回True
l1 = [10, 'Python', {1, 2, 3}, -9]
print(all(l1)) # True
# any() ====> 有一个为真即可
l2 = [0, '', None, False, 10]
print(any(l2)) # True
ps:橱窗有Python书籍,有需要的道友自行购买,让洒家赚一丢丢佣金吧