图片来源于网易课堂,大熊课堂
文章目录
什么是函数?
函数的定义?
普通参数
默认参数
关键字参数
不定长参数
函数的返回值
函数的作用域
函数嵌套
递归函数
匿名函数
创建匿名函数
函数装饰器
体验函数装饰器?
创建装饰器
?带参数的装饰器
不定长参数的装饰器
装饰器嵌套
什么是函数?
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如 print()。但你也可以自己创建函数,这被叫做用户自定义函数
(菜鸟教程)
函数的定义?
示例:
def get_requests():
print("hello")
print("函数先定义后调用哦")
# 调用
get_requests()
>>> hello
函数先定义后调用哦
普通参数
示例:
def book(one, two):
print(one)
print(two)
book('1', '2')
>>> 1
2
?由此可见,函数的普通参数是一一对应着的。
默认参数
假设我今天工作了十个小时,我的工资是每小时八块钱这是我的固定工资,那我今天应得 八十。
def working(hours, compensation=8):
print(f'你今天工作了 {hours} 小时, 现工资为:{hours * compensation}')
working(10)
>>> 你今天工作了 10 小时, 现工资为:80
节假日我的每小时工资提高到了 20 元/时,这时我的应得工资为 200
def working(hours, compensation=8):
print(f'你今天工作了 {hours} 小时, 现工资为:{hours * compensation}')
working(10, 20)
>>> 你今天工作了 10 小时, 现工资为:200
由此可见,当设置了默认参数时,不重新定义参数则使用默认参数。
关键字参数
? 关键字参数的位置不需要一一对应,因为它是使用直接赋值的方式.
def hero(name, nickname):
print(f'{nickname}:{name}')
hero(name='鲁智深', nickname='花和尚')
>>> 花和尚:鲁智深
不定长参数
简单说就是参数的长度不固定。
1. 第一种,单个星号的情况
? 在这里rags相当于一个容器,它包含着你传递过来的所有参数,默认将参数转化为元组。
def number(*args):
print(args)
for i in args:
print(i)
number(1, 2, 3, 4, 5, 6, 7, 8, 9)
>>> (1, 2, 3, 4, 5, 6, 7, 8, 9)
1
...
9
2. 第二种俩星号的情况
这个也是一个不定长参数,唯一不一样的是它转换的是字典类型。
def number(*args, **kwargs):
print(args)
print(kwargs)
number(1, 2, 3, 4, 5, 6, 7, 8, 9, name='鲁智深', nickname='花和尚')
>>> (1, 2, 3, 4, 5, 6, 7, 8, 9)
{'name': '鲁智深', 'nickname': '花和尚'}
函数的返回值
什么的返回值,简单说就是程序执行完成后得出的结果。
?示例:
def add(one, two):
return one + two
# 结果最终返回给了调用者,我们也可以给它赋值
print(add(5, 6))
>>> 11
函数的作用域
? ? ? ? 简单说局部变量就是函数内部定义的变量,局部变量与局部变量之间没有任何关系。例如:
def one():
a = 100
print(a)
def two():
a = 200
print(a)
one()
two()
>>> 100
200
? ? ? ? 全局变量即函数外定义的变量,即可以被函数内部调用。
one = 4
def add():
print(one)
add()
>>> 4
就近原则
当然函数内部没有定义使用,使用全局变量,如内部以定义则使用局部变量。
one = 1
def add():
print(one)
def two():
one = 5
print(one)
add()
two()
print(one)
>>> 1
5
1
1. 在函数修改全局变量
这是不被允许的,因为内部没有定义,但如果我声明了全局变量就可以修改了。
one = 4
def add():
one += 1
add()
>>> UnboundLocalError: local variable 'one' referenced before assignment
one = 4
def add():
global one
one += 1
print(one)
add()
print(one)
>>> 5
5
2. 局部使用全局变量,可变类型
? 这是被允许的,因为列表是可变类型动态的。
one = [1, 2, 3, 4, 5]
def add():
one.append(6)
print(one)
add()
>>> [1, 2, 3, 4, 5, 6]
总结: 局部变量:
- ?局部变量,函数内部定义的变量
- 不同函数可以有相同的变量名,不会产生影响
- 它的作用是临时保存函数中使用的数据
全局变量:
- 全局变量,函数外部定义的变量
- 对于不可变类型的全局变量,需要使用global修改全局变量
- 对于可变类型的全局变量,不使用global也可以修改
函数嵌套
1. 函数中调用其他函数
def start():
one()
two()
def one():
print('one 开始执行')
print('one 执行完成')
def two():
print('two 开始执行')
print('two 执行完成')
start()
>>> one 开始执行
one 执行完成
two 开始执行
two 执行完成
2. 在函数中创建函数
? 注:函数内部创建的函数,只能在内部调用
def start():
print('Start 开始')
def over():
print('Over 开始执行')
over()
start()
>>> Start 开始
Over 开始执行
3. 函数嵌套中的变量作用域
? 可以看出,这里的作用域与前面说的局部全局很相似,内部函数 over 没有声明变量 a 也可以调用 start 函数中的 a ,也就是如果在函数内部找不到变量 a 就去函数外面查找。
def start():
a = 10
print(f'start 中的a值为{a}')
def over():
a = 200
print(f'over 中的a值为{a}')
over()
start()
>>> start 中的a值为10
over 中的a值为200
4. 函数嵌套,修改外函数的变量
?修改外函数变量需要使用关键字 nonlocal?
def start():
a = 10
print(f'start 中的a值为{a}')
def over():
nonlocal a
a = 200
print(f'over 中的a值为{a}')
over()
print(f'外函数:{a}')
start()
>>> start 中的a值为10
over 中的a值为200
外函数:200
递归函数
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数
?示例:
? 求阶层例子
def fact(n):
if n == 1:
return 1
resutl = n * fact(n-1)
return resutl
result = fact(3)
print(result)
>>> 6
匿名函数
匿名函数,顾名思义即没有名字,匿名函数一般用于实现功能简单简短的函数。
创建匿名函数
?语法结构
?示例:
def add(x, y):
return x + y
print(add(1, 3))
adds = lambda x, y: y + x
print(adds(1, 3))
addpuls = (lambda x, y: y + x)(1, 3)
print(addpuls)
>>> 4
4
4
函数装饰器
装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短,也更Pythonic(Python范儿)
(菜鸟教程)
如果还不是很明白,那我们举个栗子吧,圣诞节到了很多商城都买了圣诞树放在门口,而树上的装饰品就类似于我们的装饰器,而树的本身还是树。
体验函数装饰器?
我们以一个计算函数运行时间的例子来演示。
1. 普通方式计算
? 像我们以前都是这样计算的,设想一下如果你要计算很多函数的运行时间,你是不是得写很多 开始时间,结束时间啥的哈,这样一来我们的代码就会非常的臃肿.
import time
def time_for():
print('time_for 开始')
for i in range(1000000):
pass
print('time_for 结束')
# 开始时间
start_time = time.perf_counter()
time_for()
# 结束时间
end_time = time.perf_counter()
print(f'time_for 运行时间为:{end_time - start_time}')
>>> time_for 开始
time_for 结束
time_for 运行时间为:0.021750199999999997
2. 利用函数的方式
? 使用函数的方式,可以让我们的代码更加简单,但还是很麻烦,这时我们的函数装饰器就出现了,下面我们就以函数装饰器来更改这个例子.
import time
# 计算程序运行时间函数
def my_time(func):
def operation():
print('operation 开始')
start_time = time.perf_counter()
func()
end_time = time.perf_counter()
print(f'函数运行时间:{end_time - start_time}')
print('operation 结束')
return operation
# 待计算函数 (一)
def time_for():
for i in range(1000000):
pass
# 待计算函数(二)
def time_while():
i = 0
while i < 1000000:
i += 1
# 计算 time_for
result = my_time(time_for)
result()
print('\n')
# 计算 time_while
new_resule = my_time(time_while)
new_resule()
>>> operation 开始
函数运行时间:0.022555599999999995
operation 结束
operation 开始
函数运行时间:0.0553232
operation 结束
3. 使用函数装饰器的方式
? 我们可以发现这个代码,比我们之前的都简洁而且更加的易于阅读,这就是函数装饰器(语法糖/魔法糖)它使用 @ 来表示装饰.
import time
# 计算程序运行时间函数
def my_time(func):
def operation():
print('operation 开始')
start_time = time.perf_counter()
func()
end_time = time.perf_counter()
print(f'函数运行时间:{end_time - start_time}')
print('operation 结束')
return operation
# 待计算函数 (一)
@my_time
def time_for():
for i in range(1000000):
pass
# 待计算函数(二)
@my_time
def time_while():
i = 0
while i < 1000000:
i += 1
# 计算 time_for 运行时间
time_for()
# 计算 time_while 运行时间
time_while()
>>> operation 开始
函数运行时间:0.0339201
operation 结束
operation 开始
函数运行时间:0.0529231
operation 结束
创建装饰器
因为这个内容不好讲,我也不会怎么讲怕误人子弟,这里就引入菜鸟教程的课程。
函数装饰器-菜鸟教程https://www.runoob.com/w3cnote/python-func-decorators.htmlhttps://www.runoob.com/w3cnote/python-func-decorators.html
?带参数的装饰器
? 代码解析:我们都知道代码从上至下开始运行,遇到函数不会自动执行,遇到 time_for 函数调用才开始执行,因为 time_for 被装饰了使用相当于调用了 my_time 而传递的参数就是 numbers,因为我们的主函数是 operation 所以自然而然的传递给它,剩下的就是传递给 func.
import time
# 计算程序运行时间函数
def my_time(func):
def operation(numbers):
print('operation 开始')
start_time = time.perf_counter()
func(numbers)
end_time = time.perf_counter()
print(f'函数运行时间:{end_time - start_time}')
print('operation 结束')
return operation
# 待计算函数 (一)
@my_time
def time_for(numbers):
for i in range(numbers):
pass
time_for(10000)
>>> operation 开始
函数运行时间:0.0004415000000000044
operation 结束
不定长参数的装饰器
? ? ? 在前面我们介绍过函数的不定长参一个 * 代表的元组,俩个 * 代表的字典,那么对于我们的装饰器我们该怎么书写呢?
?不定长参数的传递位置跟普通参数传递位置是一样的,这里只拿 单个 * 号做示例,kwargs 的方法也是如此,不同的是 kwaargs 传递时是以关键字的方式传递的.
import time
# 计算程序运行时间函数
def my_time(func):
def operation(*args):
print('operation 开始')
start_time = time.perf_counter()
func(*args)
end_time = time.perf_counter()
print(f'函数运行时间:{end_time - start_time}')
print('operation 结束')
return operation
@my_time
def welcome(*args):
name, gender = args
gender = '男士' if gender == '男' else '女士'
print(f'{name}{gender}, 新天地红楼欢迎您!')
welcome('赵日天', '男')
>>> operation 开始
赵日天男士, 新天地红楼欢迎您!
函数运行时间:8.099999999996998e-06
operation 结束
装饰器嵌套
?函数装饰器嵌套,直白说就是一个函数引用了多个装饰器的情况,装饰器嵌套调用时需要注意它的顺序,先调用离它最近的装饰器.
?示例:
def my_one(func):
def my_decoration_one(name):
func(name)
print('my_one 函数启动')
return my_decoration_one
def my_two(func):
def my_decoration_two(name):
print('my_two 函数启动')
func(name)
return my_decoration_two
@my_one
@my_two
def welcome(name):
print(f'代号:{name}')
welcome('赵日天')
>>> my_two 函数启动
代号:赵日天
my_one 函数启动
|