函数的定义
- 函数定义不会执行函数的代码, 在内存中保存函数的名字
- 函数名需要满足标识符规则, 以数字, 字母和下划线组成, 不能以数字开头,不能和关键字重名
# 定义函数 func()
def func():
print('人生苦短')
print("我用python")
函数的调用
- 函数调用, 才会执行函数中的代码
- 函数必须先定义后使用
- 函数调用的时候,才会执行, 会在内存中去找函数名, 找到了就会执行, 没找到就会报错
# 定义函数
def func():
print('人生苦短')
print("我用python")
func()
# 控制台输出
人生苦短
我用python
函数的参数
- 想让函数更加的通用,在函数外部将数据值传递到函数内使用( 在函数调用的时候, 给他数据值 )
- 而这个数据值就是参数, 参数分为形参, 和实参
- 形参: 在函数定义时, 括号中的变量, 称为形参, 相当于是具体数据的占位(作用域 : 函数内部)
- 实参: 在函数调用的时候, 括号中的数据值, 称为实参, 会将实参的数据值传递给形参 ( 实参的个数必须和形参的个数保持一致, 否则会报错)
# 定义函数
def my_sum(num1, num2): # num1 和 num2 称为形式参数, 形参, 给实际的数据占位
"""求 num1 + num2 的和"""
# 形参的使用范围: 只能在函数内部使用
num = num1 + num2
print(num)
# 函数的调用
my_sum(1, 2) # 1 和 2 就称为实参, 实参, 将 1 和 2 的值传递给 num1 和 num2
my_sum(100, 200) # 函数的实参的个数和形参的个数需要保持一致, 如果少实参, 则会报错
局部变量
定义在函数内部的变量, 称为局部变量
- 局部变量能否在函数外部使用 —> 不能
- 是否可以再其他函数中定义相同名字的局部变量 —> 可以再不同函数内部定义相同名字的局部变量, 两者之间没有影响
- 局部变量的作用域: 当前函数内部
- 生命周期: 在函数内部定义开始, 到函数结束为止
# 定义一个函数
def func():
""" num 就是局部变量"""
num = 100
print(100)
# 函数调用
func()
# print(num) # 程序报错, 局部变量不能再函数外部使用
# 控制台输出
100
全局变量
定义在函数外部的变量, 称为全局变量
- 定义的全局变量,可以在函数内部读取
- 定义的全局变量, 不可以自函数内部直接修改
- 在函数内部不能直接修改全局变量, 想要在函数内部修改全局变量的值, 需要使用 golbal 声明
# 定义一个全局变量
g_num = 10
# 定义一个函数, 看是否可以读取 ---> 可以
def read_num():
print("read_num", g_num)
# 函数的调用
read_ num()
# 控制台输出
read_num 10
# 定义函数, 看是否可以修改全局变量的值 ---> 不可以
def write_num():
#本意是修改全局变量的值, 但实际上实在函数内部定义一个局部变量 g_num
g_num = 100
print("write_num", g_num)
# 调用函数
write_num()
# 控制台输出
write_num 100
#定义一个函数, 在函内部修改全局变量的值, 需要使用global声明
def write_num1():
# 在使用全局变量之前, 使用 global 声明
global g_num
g_num = 1000
print("write_num1", g_num)
# 调用函数
write_num1()
read_ num() # 判断全局变量是否被修改,之前函数 read_num() 输出的是 read_num 10
# 控制台输出
write_num1 1000
read_num 1000
返回值
- 返回值就是函数执行的结果, 会将执行的结果进行返回 ( eg. input() 的返回值是输入的内容, print() 的返回值是 None)
- 使用 return 返回 —> return 数据值
- 函数内部中定义的局部变量, 或者是函数执行的结果, 需要在函数外部使用.,需要使用 return 将局部变量或者是函数执行的结果, 返回给外部
- return 会结束函数的执行, return 之后的代码不会执行
- return 只能在函数中使用
# 定义一个函数
def my_sum(num1, num2):
# 函数默认返回的是 None
num = num1 + num2
# 可以使用 return 将程序中的数据但会
return num # return 会结束函数的执行, return 之后的代码不会被执行
result = my_sum(10, 20)
print(my_sum(10, 20))
# 在函数外部需要将求和的结果和字符串连接
print('求和的结果是%d' % result)
# 控制台输出
30
求和的结果是30
函数的嵌套
def test_b():
print('--- testb start ---')
print('这里是函数 testb 执行的代码')
print('--- testb end ---')
def test_a():
print('--- testa start ---')
test_b()
print('--- test end ---')
test_a()
# 执行的结果
--- testa start ---
--- testb start ---
这里是函数 testb 执行的代码
--- testb end ---
--- testa end ---
def my_sum(a, b, c):
"""对3个数求和"""
num = a + b + c
return num
def average3number(a, b, c):
# 先求和
num = my_sum(a, b, c)
# 求平均数
avg = num / 3
return avg
num1 = my_sum(10, 20, 30)
print(num1)
num2 = average3number(10, 20, 30)
print(num2)
# 控制台输出
60
20.0
函数嵌套应用举例
def print_line1(char, num):
"""打印一行字符"""
print(char * num)
def print_line(line, char, num):
"""打印多行"""
for i in range(line):
print_line1(char, num)
print_line(5, *, 20)
# 控制台输出
********************
********************
********************
********************
********************
函数的传参方式
- 位置传参(位置实参): 普通的传参方式,直写数据值
- 按照形参的顺序获取实参的值
- 关键字传参(关键字实参) : 指定将数据 (实参) 给哪个形参, 关键字必须要存在
- 混合使用需要注意(1, 换剪子实参要放在位置实参的后边. 2, 不能对一个形参给多个值)
def func(a, b, c)
print(f'a: {a}, b: {b}, c: {c}')
# 位置传参
func(1, 2, 3)
# 关键字传参 关键字实参必须是存在的形参
func(c=1, b=2, a=3)
# func(cc=1, b=2, a=3) # 程序报错, cc 不是形参值
# 位置传参和关键字传参混合使用
func(20, 30, c=10)
# func(c=10, 20, 30) # 程序报错, 位置实参必须在关键字实参之前
# func(10, 20, b=30) # 程序报错, 形参 b 多获得了多个值
# 控制台输出
a: 1, b : 2, c : 3
a: 3, b : 2, c : 1
a: 20, b : 30, c : 10
缺省参数
缺省参数: 在函数定义的时候, 给形参一个数据值, 那这个形参就称为缺省参数
- 函数调用的时候, 如果给缺省形参传递实参值, 使用传递的数据值
- 如果不给缺省形参传递数据值, 使用的默认值
不定长参数
- 不定长参数(形参): 参数的个数是不确定的, 可以接收多个
- 不定长位置参数(不定长元组参数): 可以接收所有的位置实参
- 不定长关键字参数(不定长字典参数): 可以接收所有的关键字实参
# 不定长元组形参(写在普通形参的后边)
def my_sum(*args): # 使用 * 标记, 使 args 变为不定长元组形参
"""求和函数"""
print(args)
num = 0
for i in args:
num += 1
# 使用 return 将求和结果返回
return num
print(my_sum(10, 20))
print(my_sum(10, 20, 30))
# 不定长字典参数
def show_info(**kwargs): # 需要使用 ** 做标记, kwarg 就是一个字典, 变成字典参数
"""
打印信息
:param name
:param age
:param height
:param weight
"""
print(kwargs)
name = kwargs.get('name', '未填写')
age = kwargs.get('name', '未填写')
height = kwargs.get('height', '未填写')
weight = kwargs.get('weight', '未填写')
print(name, age, height, weight)
pass
show_info(name='qym')
show_info(name='小王')
show_info(name='小王', age=18)
# 控制台输出
(10, 20)
30
(10, 20, 30)
60
{'name': 'isaac'}
isaac 未填写 未填写 未填写
{'name': '小王'}
小王 未填写 未填写 未填写
{'name': '小王', 'age': 18}
小王 18 未填写 未填写
完整的形参顺序
完整的形参顺序: 普通,不定长元祖形参, 缺省参数, 不定长字典形参
- 不能将缺省参数放在 * args (不定长元祖参数)前边 —> 不能这样定义SyntaxError: positional argument follows keyword argument 位置的实参放在了关键字后边
def show_info(name, *args, age=18, **kwargs)
print('name', name)
print('args', args)
print('age', age)
print('kwargs', kwargs)
pass
show_info('qym', 1, 2, 3, age=20, a=10, b=20)
print('-' * 20)
show_info('qym', 1, 2, 3, 4, a=10, b=20)
print('-' * 20)
a = [1, 2, 3]
b = {'a': 10, 'b': 20}
show_info('qym', *a, **b)
# 控制台输出
name qym
args (1, 2, 3)
age 20
kwargs {'a': 10, 'b': 20}
---------------------------
name qym
args (1, 2, 3, 4)
age 18
kwargs {'a': 10, 'b': 20}
---------------------------
name qym
args (1, 2, 3)
age 18
kwargs {'a': 10, 'b': 20}
引用
- id(变量) 可以查看变量中存储的引用值
- 引用是对内存地址的封装, 引用值一样, 代表着内存也是一样的
- 使用赋值运算符= , 会改变引用值
- 变量1 = 变量2 (将变量 2 的引用给到变量1, 变量1 和变量 2 的引用值是一样的, 指向同一块内存)
- 变量3 = 数据 (开辟新的内存空间, 会将数据的地址给到变量3)
- 字符串和整数, 会有一个优化(优化内存,如果值相等的话,会使用同一个地址)
可变和不可变类型
可变和不可变类型: 在不改变变量引用的前提下, 能否直接修改变量中的内容
- 能修改则为可变类型: 字典 dict 列表 list 集合 set
- 不能修改则为不可变类型: 整数 int 小数 float 字符串 str 元组 tuple
# 可变类型 list
my_list = [1, 2]
print(id(my_list1))
my_list.append(3) # 没有修改变量 my_list 的引用
print(my_list1)
print(id(my_list1))
my_list1[0] = 100 # 没有修改变量 my_list 的引用
print(id(my_list1))
my_list1 = [1]
print(my_list1)
print(id(my_list1))
print('*' * 30)
# 不可变类型 int
num = 1
print(id(num))
num = 2
print(id(num))
print('-' * 30)
# 不可变类型 字符串
my_str = 'hello world'
print(id(my_str))
my_str1 = my_str.replace('1', 'L')
print(id(my_list))
print(id(my_list1))
print('*' * 30)
# 不可变类型 元组
my_tuple = (1, 2, [3, 4])
print(id(my_tuple))
my_tuple[2][0] = 10 # 没有修改变量 my_tuple 的引用
print(my_tuple)
print(id(my_tuple))
# my_tuple[1] = 12 # 程序出错, 不能修改元组中的数据
# print(my_tuple)
# print(id(my_tuple))
# 控制台输出
2612553783304
[1, 2, 3]
2612553783304
2612553783304
[1]
2612553783496
******************************
1945487024
1945487056
------------------------------
2612553782512
2612553782512
2612553784944
******************************
2612553714784
(1, 2, [10, 4])
2612553714784
组包和拆包
组包(pack) : 把等号 = 右边多个数据包装成元组
拆包(unpack) : 等号左边的变量来接收等号右边的多个数据值[ 变量的个数和数据元素的个数要相等]
# 组包 把等号右边多个数据包装成元组
num = 1, 2, 3
print(num, type(num))
"""
拆包: 等号左边的变量和接受等号右边的多个数据值
变量的个数和数据元素的个数要相等
"""
a, b, c = 10, 20, 30
print(f'a: {a}, b: {b}, c: {c}')
# 应用1. 交换两个变量的值
a = 100
b = 200
a, b = b, a
print(a, b)
print('-' * 30)
# 应用2. 函数返回多个值, 组包
def func()
return 1, 2, 3 # 组包
num1 = func()
print(num1)
a, b, c = func()
print(f'a: {a}, b: {b}, c: {c}')
# 应用3. 字典遍历键值对的时候
my_dict = {'a': 100, ; 'b': 200, 'c': 300}
for key, value in my_dict:
print(key, value)
# 控制台输出
(1, 2, 3) <class 'tuple'>
a: 10,b: 20,c: 30
200 100
------------------------------
(1, 2, 3)
a: 1,b: 2,c: 3
a 100
b 200
c 300