1. 函数的定义与使用
def greet_user():
"""显示简单的问候语"""
print("Hello!")
greet_user() #Hello!
这个示例演示了最简单的函数结构。使用关键字def来告诉Python你要定义一个函数。
定义函数时,要向Python指出了函数名,还可能在括号内指出函数需要的参数。
在这里,函数名为greet_user() ,它不需要任何参数,因此括号是空的(即便如此,括号也必不可少)。
最后,定义以冒号结尾。
函数在进行使用时必须要带上“()”,否则无法使用。
2. 函数的参数
2.1 位置参数
你调用函数时,Python必须将函数调用中的每个实参都关联到函数定义中的一个形参。
为此,最简单的关联方式是基于实参的顺序。这种关联方式被称为位置实参。
def describe_pet(animal_type, pet_name):
"""显示宠物的信息"""
print("\nI have a " + animal_type + ".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
#相同的位置相对应,因此位置实参的实参位置很重要。
describe_pet('hamster', 'harry')
"""I have a hamster.
My hamster's name is Harry."""
2.2 默认参数
编写函数时,可给每个形参指定默认值 。在调用函数中给形参提供了实参时,Python将使用指定的实参值;
否则,将使用形参的默认值。因此,给形参指定默认值后,可在函数调用中省略相应的实参。
def describe_pet(pet_name, animal_type='dog'):
"""显示宠物的信息"""
print("\nI have a " + animal_type + ".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
# 调用这个函数时,如果没有给animal_type 指定值,Python将把这个形参设置为'dog'。
describe_pet(pet_name='willie')
"""I have a dog.
My dog's name is Willie."""
由于给animal_type 指定了默认值,无需通过实参来指定动物类型,因此在函数调用中只包含一个实参——宠物的名字。
然而,Python依然将这个实参视为位置实参,因此如果函数调用中只包含宠物的名字,这个实参将关联到函数定义中的第一个形参。
这就是需要将pet_name 放在形参列表开头的原因所在。
因此上述结果也可用另种方式表示:
describe_pet('willie')
如果要描述的动物不是小狗,可使用类似于下面的函数调用:
describe_pet(pet_name='harry', animal_type='hamster')
由于显式地给animal_type 提供了实参,因此Python将忽略这个形参的默认值。
2.3 关键字参数
关键字实参是传递给函数的名称对。你直接在实参中将名称和值关联起来了,因此向函数传递实参时不会混淆。
def describe_pet(animal_type, pet_name):
"""显示宠物的信息"""
print("\nI have a " + animal_type + ".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
describe_pet(animal_type='hamster', pet_name='harry')
"""
I have a harry.
My harry's name is Hamster."""
关键字实参的实参顺序不重要。
2.4 可变参数
简单可变参数:*args
有时候,你预先不知道函数需要接受多少个实参,Python允许函数从调用语句中收集任意数量的实参。
def make_pizza(*toppings):
"""打印顾客点的所有配料"""
print(toppings)
make_pizza('pepperoni') #('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese') #('mushrooms', 'green peppers', 'extra cheese')
形参名toppings 中的星号让Python创建一个名为toppings 的空元组,并将收到的所有值都封装到这个元组中。
可以将位置参数、关键字参数和可变参数相结合。
此时必须在函数定义中将接纳任意数量实参的形参放在最后。
Python先匹配位置实参和关键字实参,再将余下的实参都收集到最后一个形参中。
def make_pizza(size, *toppings):
"""概述要制作的比萨"""
print("\nMaking a " + str(size) + "-inch pizza with the following toppings:")
for topping in toppings:
print("- " + topping)
make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
"""Making a 16-inch pizza with the following toppings:
- pepperoni
Making a 12-inch pizza with the following toppings:
- mushrooms
- green peppers
- extra cheese"""
键值对可变参数:**kwargs
有时候,需要接受任意数量的实参,但不知道这些参数是什么类型的数据。
在这种情况下,可将函数参数编写成能够接受任意数量的键值对。
def build_profile(first, last, **user_info):
"""创建一个字典,其中包含我们知道的有关用户的一切"""
profile = {}
profile['001'] = first
profile['002'] = last
for key, value in user_info.items():
profile[key] = value
return profile
user_info = {'003':'王五'}
user_profile = build_profile('张三', '李四', **user_info)
print(user_profile) #{'001': '张三', '002': '李四', '003': '王五'}
形参user_info 中的两个星号让Python创建一个名为user_info 的空字典,并将收到的所有名称—值对都封装到这个字典中。
在这个函数中,可以像访问其他字典那样访问user_info 中的键值对。
编写函数时,你可以以各种方式混合使用位置实参、关键字实参和任意数量的实参。
3. 函数返回值
3.1 简单返回值
def get_formatted_name(first_name, last_name):
"""返回整洁的姓名"""
full_name = first_name + ' ' + last_name
return full_name.title()
musician = get_formatted_name('jimi', 'hendrix')
print(musician) #Jimi Hendrix
3.2 返回字典
函数可返回任何类型的值,包括列表和字典等较复杂的数据结构。
def build_person(first_name, last_name):
"""返回一个字典,其中包含有关一个人的信息"""
person = {'first': first_name, 'last': last_name}
return person
musician = build_person('jimi', 'hendrix')
print(musician) #{'first': 'jimi', 'last': 'hendrix'}
3.3 返回值特点
- 若返回了x个结果,且有x个接收值,则返回值与接收值之间一一对应
- 若返回了x个结果,但只有1个接收值,则返回值形成元组赋值给唯一的接收值
4. 变量与内部函数
4.1 局部变量与全局变量
局部变量
声明在函数内部,仅限函数内部使用
全局变量
声明在函数外部,所有变量可以访问
局部变量可以在函数内部修改,当全局变量不可变时,不可随意在函数内部修改,要使用global
例如list全局变量是可变的,字符串全局变量是不可变的
4.2 内部函数
内部函数是指定义在函数内部的函数
内部函数的特点:
- 内部函数可以访问外部函数的变量
- 内部函数可以修改外部函数的可变变量
- 内部函数修改全局变量的不可变变量时,需要在内部函数声明:global 变量名
- 内部函数修改外部函数的不可变的变量时,需要在内部函数中声明:nonlocal 变量名
- locals()查看本地变量有哪些,以字典的形式输出
- globals()查看全局变量有哪些,以字典形式输出,存在系统键值对
def func1():
# 声明变量
n = 100 # 局部变量
list = [1,3,6,0]
def func2():
# 使用nonlocal使内部函数可以使用局部不可变变量
nonlocal n
y = 0
for i in list:
list[y] += n
y += 1
n += 1
func2()
print(n)
print(list)
func1()
#101
#[101, 103, 106, 100]
# 全局变量
a = 100
print(globals())
def func():
#局部变量
b = 99
def func1():
# 对于全局变量a的声明必须在内部函数中
global a
nonlocal b
c = 98
c += 1
b += 1
a += 1
print(c)
print(b)
print(a)
func1()
print(locals())#{'func1': <function func.<locals>.func1 at 0x000001B927A290D8>, 'b': 100}
func()
"""99
100
101"""
5. 函数的闭包
5.1 闭包的概念
外部函数通过return将内部函数返回的形式叫做闭包
形成条件:
- 外部函数中定义了内部函数
- 外部函数是有返回值
- 返回的值是:内部函数名
- 内部函数引用了外部函数的变量
def func1():
a = 100
def func2():
b = 99
print(a,b)
return func2
x = func1()
print(x) #<function func1.<locals>.func2 at 0x00000273B56290D8>
x() #100 99
5.2 闭包保存参数状态
def func1(a, b):
c = 1
def func2():
s = a + b + c
print(s)
return func2
x = func1(10,4)
y = func1(3, 7)
y() #11
x() #15
6. 装饰器
6.1 装饰器的概念
装饰器的特点:
- 函数作为参数传递给另一函数
- 要有闭包的特点
- 原函数func1带参数,则wrapper函数必须带参数,并传给内部的func1
def decorate(func):
a = 100
print('进行操作1')
def wrapper(): #若参数为(*args,**kwargs)则为万能装饰器
func()
print("进行操作2")
print('进行操作3')
return wrapper
# 使用装饰器
@decorate
def func1():
print('进行操作4')
"""
进行操作1
进行操作3
"""
func1()
"""
进行操作1
进行操作3
进行操作4
进行操作2
"""
"""
1.func1被装饰函数
2.将被装饰函数作为参数传给装饰器decorate
3.执行decorate函数
4.将decorate函数返回值又赋值给house
"""
6.2 装饰器的参数问题
原函数带参数
原函数的参数问题分为以下几种情况:
- 原函数带一个参数:wrapper函数必须带参数
- 原函数带未知个参数:wrapper函数带参数*args
- 原函数带默认参数:wrapper函数带参数**kwargs
- 无论原函数带什么参数:都可使用(args,*kwargs)
装饰器带参数
带参数的装饰器是三层的,最外层的函数负责接收装饰器参数,里面的内容还是原装饰器的内容
# 装饰器带参数
def outer(a): # 第一层
def decorate(func): # 第二层
def wrapper(*args,**kwargs): # 第三层
func(*args)
print('---->铺地砖{}快'.format(a))
return wrapper # 返回出来的是:第三层
return decorate # 返回出来的是:第二层
@outer(10)
def house(time):
print('我{}日期拿到房子'.format(time))
@outer(100)
def stree():
print('修建街道')
house('2020-07-18')
stree()
"""我2020-07-18日期拿到房子
---->铺地砖10快
修建街道
---->铺地砖100快"""
6.3 多层装饰器
一个原函数可使用多个装饰器修饰,先执行最近的装饰器,将其内部函数作为另一个装饰器的参数进行执行下一个装饰器
7. 匿名函数
7.1 匿名函数的格式
lambda 参数1,参数2 : 运算
# 匿名函数
s = lambda a,b : a + b
print(s)
result = s(1,2) #<function <lambda> at 0x00000176A4AFFAF8>
print(result) #3
def func(a,b, func1):
result = func1(a,b)
print(result)
func(2,5,lambda x,y : x*y) #10