写点什么

深入浅出 Python——Python 高级语法之函数

作者:何极光
  • 2022-10-25
    陕西
  • 本文字数:4804 字

    阅读完需:约 16 分钟

深入浅出Python——Python高级语法之函数

前言:本博文主要讲解 Python 函数的用法,属于 Python 高级语法。基础语法见:https://xie.infoq.cn/article/a1b348be0074e38f1b307f50a,更多内容请访问博主的主页,谢谢!

一. 函数的作用

函数就是将一段具有独立功能的代码块 整合到一个整体并命名,在需要的位置调用这个名称即可完成对应的需求。


函数在开发过程中,可以更高效的实现代码重用。

二. 函数的使用步骤

1. 定义函数

def 函数名(参数):    代码1    代码2    ......
复制代码

2. 调用函数

函数名(参数)
复制代码


注意:


  1. 不同的需求,参数可有可无。

  2. 在 Python 中,函数必须先定义后使用。


==一定是先定义函数,后调用函数。==

三. 函数的参数作用

思考:完成需求如下:一个函数完成两个数 1 和 2 的加法运算,如何书写程序?


# 定义函数def add_num1():    result = 1 + 2    print(result)

# 调用函数add_num1()
复制代码


思考:上述 add_num1 函数只能完成数字 1 和 2 的加法运算,如果想要这个函数变得更灵活,可以计算任何用户指定的两个数字的和,如何书写程序?


分析:用户要在调用函数的时候指定具体数字,那么在定义函数的时候就需要接收用户指定的数字。函数调用时候指定的数字和定义函数时候接收的数字即是函数的参数。


# 定义函数时同时定义了接收用户数据的参数a和b,a和b是形参def add_num2(a, b):    result = a + b    print(result)

# 调用函数时传入了真实的数据10 和 20,真实数据为实参add_num2(10, 20)
复制代码


函数的参数:函数调用的时候可以传入真实数据,增大函数的使用的灵活性。


  • 形参:函数定义时书写的参数(非真实数据)

  • 实参:函数调用时书写的参数(真实数据)

四. 函数的返回值作用

例如:我们去超市购物,比如买烟,给钱之后,是不是售货员会返回给我们烟这个商品,在函数中,如果需要返回结果给用户需要使用函数返回值。


def buy():    return '烟'
# 使用变量保存函数返回值goods = buy()print(goods)
复制代码


需求:制作一个计算器,计算任意两数字之和,并保存结果。


def sum_num(a, b):    return a + b

# 用result变量保存函数返回值result = sum_num(1, 2)print(result)
复制代码


函数的返回值


  • 作用:函数调用后,返回需要的计算结果

  • 写法


return 表达式
复制代码

五. 函数的说明文档

思考:定义一个函数后,程序员如何书写程序能够快速提示这个函数的作用?


答:注释


思考:如果代码多,我们是不是需要在很多代码中找到这个函数定义的位置才能看到注释?如果想更方便的查看函数的作用怎么办?


答:函数的说明文档


函数的说明文档也叫函数的文档说明。

1. 语法

  • 定义函数的说明文档


def 函数名(参数):    """ 说明文档的位置 """    代码    ......
复制代码


  • 查看函数的说明文档


help(函数名)
复制代码

2. 快速体验

def sum_num(a, b):    """ 求和函数 """    return a + b

help(sum_num)
复制代码



函数的说明文档


  • 作用:保存函数解释说明的信息

  • 写法


def 函数名():    """ 函数说明文档 """
复制代码

六. 函数嵌套调用

所谓函数嵌套调用指的是==一个函数里面又调用了另外一个函数==。


  • 示例


def testB():    print('---- testB start----')    print('这里是testB函数执行的代码...(省略)...')    print('---- testB end----')
def testA(): print('---- testA start----') testB() print('---- testA end----')
testA()
复制代码


  • 效果



  • 执行流程


如果函数 A 中,调用了另外一个函数 B,那么先把函数 B 中的任务都执行完毕之后才会回到上次 函数 A 执行的位置。

七. 函数应用

1. 打印图形

  1. 打印一条横线


def print_line():    print('-' * 20)

print_line()
复制代码



  1. 打印多条横线


def print_line():    print('-' * 20)

def print_lines(num): i = 0 while i < num: print_line() i += 1

print_lines(5)
复制代码


2. 函数计算

  1. 求三个数之和


def sum_num(a, b, c):    return a + b + c

result = sum_num(1, 2, 3)print(result) # 6
复制代码


  1. 求三个数平均值


def average_num(a, b, c):    sumResult = sum_num(a, b, c)    return sumResult / 3
result = average_num(1, 2, 3)print(result) # 2.0
复制代码

八. 变量作用域

变量作用域指的是变量生效的范围,主要分为两类:==局部变量==和==全局变量==。


  • 局部变量


所谓局部变量是定义在函数体内部的变量,即只在函数体内部生效。


def testA():    a = 100
print(a)

testA() # 100print(a) # 报错:name 'a' is not defined
复制代码


变量 a 是定义在testA函数内部的变量,在函数外部访问则立即报错。


局部变量的作用:在函数体内部,临时保存数据,即当函数调用完成后,则销毁局部变量。


全局变量:指的是在函数体内、外都能生效的变量。


思考:如果有一个数据,在函数 A 和函数 B 中都要使用,该怎么办?

答:将这个数据存储在一个全局变量里面。


# 定义全局变量aa = 100

def testA(): print(a) # 访问全局变量a,并打印变量a存储的数据

def testB(): print(a) # 访问全局变量a,并打印变量a存储的数据

testA() # 100testB() # 100
复制代码


思考:testB函数需求修改变量 a 的值为 200,如何修改程序?


a = 100

def testA(): print(a)

def testB(): a = 200 print(a)

testA() # 100testB() # 200print(f'全局变量a = {a}') # 全局变量a = 100
复制代码


思考:在testB函数内部的a = 200中的变量 a 是在修改全局变量a吗?


答:不是。观察上述代码发现,15 行得到 a 的数据是 100,仍然是定义全局变量 a 时候的值,而没有返回


testB函数内部的 200。综上:testB函数内部的a = 200是定义了一个局部变量。


思考:如何在函数体内部修改全局变量?


a = 100

def testA(): print(a)

def testB(): # global 关键字声明a是全局变量 global a a = 200 print(a)

testA() # 100testB() # 200print(f'全局变量a = {a}') # 全局变量a = 200
复制代码

九. 多函数程序执行流程

一般在实际开发过程中,一个程序往往由多个函数(后面知识中会讲解类)组成,并且多个函数共享某些数据,如下所示:


  • 共用全局变量


# 1. 定义全局变量glo_num = 0

def test1(): global glo_num # 修改全局变量 glo_num = 100

def test2(): # 调用test1函数中修改后的全局变量 print(glo_num)
# 2. 调用test1函数,执行函数内部代码:声明和修改全局变量test1()# 3. 调用test2函数,执行函数内部代码:打印test2() # 100
复制代码


  • 返回值作为参数传递


def test1():    return 50

def test2(num): print(num)

# 1. 保存函数test1的返回值result = test1()

# 2.将函数返回值所在变量作为参数传递到test2函数test2(result) # 50
复制代码

十. 函数的返回值

思考:如果一个函数如些两个 return (如下所示),程序如何执行?


def return_num():    return 1    return 2

result = return_num()print(result) # 1
复制代码


答:只执行了第一个 return,原因是因为 return 可以退出当前函数,导致 return 下方的代码不执行。


思考:如果一个函数要有多个返回值,该如何书写代码?


def return_num():    return 1, 2

result = return_num()print(result) # (1, 2)
复制代码


注意:

  1. return a, b写法,返回多个数据的时候,默认是元组类型。

  2. return 后面可以连接列表、元组或字典,以返回多个值。

十一. 函数的参数

1. 位置参数

位置参数:调用函数时根据函数定义的参数位置来传递参数。


def user_info(name, age, gender):    print(f'您的名字是{name}, 年龄是{age}, 性别是{gender}')

user_info('TOM', 20, '男')
复制代码


注意:传递和定义参数的顺序及个数必须一致。

2. 关键字参数

函数调用,通过“键=值”形式加以指定。可以让函数更加清晰、容易使用,同时也清除了参数的顺序需求。


def user_info(name, age, gender):    print(f'您的名字是{name}, 年龄是{age}, 性别是{gender}')

user_info('Rose', age=20, gender='女')user_info('小明', gender='男', age=16)
复制代码


注意:函数调用时,如果有位置参数时,位置参数必须在关键字参数的前面,但关键字参数之间不存在先后顺序。

3. 缺省参数

缺省参数也叫默认参数,用于定义函数,为参数提供默认值,调用函数时可不传该默认参数的值(注意:所有位置参数必须出现在默认参数前,包括函数定义和调用)。


def user_info(name, age, gender='男'):    print(f'您的名字是{name}, 年龄是{age}, 性别是{gender}')

user_info('TOM', 20)user_info('Rose', 18, '女')
复制代码


注意:函数调用时,如果为缺省参数传值则修改默认参数值;否则使用这个默认值。

4. 不定长参数

不定长参数也叫可变参数。用于不确定调用的时候会传递多少个参数(不传参也可以)的场景。此时,可用包裹(packing)位置参数,或者包裹关键字参数,来进行参数传递,会显得非常方便。


  • 包裹位置传递


def user_info(*args):    print(args)

# ('TOM',)user_info('TOM')# ('TOM', 18)user_info('TOM', 18)
复制代码


注意:传进的所有参数都会被 args 变量收集,它会根据传进参数的位置合并为一个元组(tuple),args 是元组类型,这就是包裹位置传递。


  • 包裹关键字传递


def user_info(**kwargs):    print(kwargs)

# {'name': 'TOM', 'age': 18, 'id': 110}user_info(name='TOM', age=18, id=110)
复制代码


综上:无论是包裹位置传递还是包裹关键字传递,都是一个组包的过程。

十二. 拆包和交换变量值

1. 拆包

  • 拆包:元组


def return_num():    return 100, 200

num1, num2 = return_num()print(num1) # 100print(num2) # 200
复制代码


  • 拆包:字典


dict1 = {'name': 'TOM', 'age': 18}a, b = dict1
# 对字典进行拆包,取出来的是字典的keyprint(a) # nameprint(b) # age
print(dict1[a]) # TOMprint(dict1[b]) # 18
复制代码

2. 交换变量值

需求:有变量a = 10b = 20,交换两个变量的值。


  • 方法一


借助第三变量存储数据。


# 1. 定义中间变量c = 0
# 2. 将a的数据存储到cc = a
# 3. 将b的数据20赋值到a,此时a = 20a = b
# 4. 将之前c的数据10赋值到b,此时b = 10b = c
print(a) # 20print(b) # 10
复制代码


  • 方法二


a, b = 1, 2a, b = b, aprint(a)  # 2print(b)  # 1
复制代码

十三. 引用

1. 了解引用

在 python 中,值是靠引用来传递来的。


我们可以用id()来判断两个变量是否为同一个值的引用。 我们可以将 id 值理解为那块内存的地址标识。


# 1. int类型a = 1b = a
print(b) # 1
print(id(a)) # 140708464157520print(id(b)) # 140708464157520
a = 2print(b) # 1,说明int类型为不可变类型
print(id(a)) # 140708464157552,此时得到是的数据2的内存地址print(id(b)) # 140708464157520

# 2. 列表aa = [10, 20]bb = aa
print(id(aa)) # 2325297783432print(id(bb)) # 2325297783432

aa.append(30)print(bb) # [10, 20, 30], 列表为可变类型
print(id(aa)) # 2325297783432print(id(bb)) # 2325297783432
复制代码

2. 引用当做实参

代码如下:


def test1(a):    print(a)    print(id(a))
a += a
print(a) print(id(a))

# int:计算前后id值不同b = 100test1(b)
# 列表:计算前后id值相同c = [11, 22]test1(c)
复制代码


十四. 可变和不可变类型

所谓可变类型与不可变类型是指:数据能够直接进行修改,如果能直接修改那么就是可变,否则是不可变。


  • 可变类型

  • 列表

  • 字典

  • 集合

  • 不可变类型

  • 整型

  • 浮点型

  • 布尔

  • 字符串

  • 元组

十五. 总结

  • 变量作用域

  • 全局:函数体内外都能生效

  • 局部:当前函数体内部生效

  • 函数多返回值写法


return 表达式1, 表达式2...
复制代码


  • 函数的参数

  • 位置参数

  • 形参和实参的个数和书写顺序必须一致

  • 关键字参数

  • 写法: key=value

  • 特点:形参和实参的书写顺序可以不一致;关键字参数必须书写在位置参数的后面

  • 缺省参数

  • 缺省参数就是默认参数

  • 写法:key=vlaue

  • 不定长位置参数

  • 收集所有位置参数,返回一个元组

  • 不定长关键字参数

  • 收集所有关键字参数,返回一个字典


引用:Python 中,数据的传递都是通过引用。


==友情链接:==


  1. 深究Python中的递归【建议收藏】

  2. 浅谈Python匿名函数(lambda表达式)

  3. 浅谈Python高阶函数

  4. Python学员管理系统【函数实现】

  5. 深入浅出Python——Python高级语法之文件操作


发布于: 2022-10-25阅读数: 39
用户头像

何极光

关注

路虽远,行则必至! 2022-10-25 加入

何程龙,计算机科学与技术专业毕业,现就任前端开发工程师。曾荣获:InfoQ写作社区专家博主、CSDN博客专家、签约讲师,中国开源协会-开发分会管理委员会委员。擅长Web前端、JavaScript框架、PythonWeb等领域及技术。

评论

发布
暂无评论
深入浅出Python——Python高级语法之函数_Python_何极光_InfoQ写作社区