文章目录
- 一、什么是函数?
- 二、函数的基础构成!
- 三、函数的参数。
- 位置参数
- 关键字参数
- 缺省参数
- 不定长参数-位置参数
- 不定长参数-关键字参数
- 四、函数的返回值。
- 五、函数返回值的进阶玩法!
- 六、函数的说明文档。
- 七、局部变量、全局变量和global关键字。
- 八、异常处理。
- 练习题
一、什么是函数?
前面我们已经学习并使用过 print()、input() 这类内置函数,相信大家一定有一些思考,了解到这些内置函数,其实就是将一些功能组合起来,通过 函数名 可以直接使用,而这类函数,其实我们也可以 自己创建。
甚至我们可以在原有 函数(或内置函数) 基础上,根据自己需要,再次创建一个新的函数,从而实现更为复杂的功能。
接下来,我们可以快速的使用代码来体会下 “函数” 的意义!
# 我们的需求:创建一个函数,每使用该函数1次,即打印100次“我钟意你!”
# 创建一个py文件,代码内容如下。
def say_love():for i in range(0, 100):print("我钟意你!")say_love()
我们可以看到,每调用一次“say_love()函数”控制台的重复输出了100次“我钟意你!”。
那 函数 带来的意义有哪些?
- 减少重复代码。
- 减少更新代码的代价。
- 代码变得更 “短、易读、更新” 。
二、函数的基础构成!
通过前面的样例,我们大致能够猜出 函数的基础构成,有哪些?
def # 定义函数的关键字。
(如果你仔细学习过《第3章》布尔值部分,你会发现def属于关键字。)
say_love():
# say_love 函数名,之前有讲过函数命名规则。
# () 参数,函数内的方法,通过接收参数,实现功能,比如print(),可以接收“字符串”,打印到控制台。之后我们会详细讲解“参数”的作用和使用。(注:空括号,表示该函数不需要接收参数)
#: 这个没什么好解释的,固定格式,必须在()之后,添加这个符号。
# 代码块,即该函数实现的功能具体代码块,具体写法本章节会细讲。
for i in range(0, 100):print("我钟意你!")
那么我们改进下这个函数,加入“参数”,看看效果。
# 根据参数num,打印num次"我钟意你!"。
# 你会发现,在调用函数时,需要传入一个参数,这个参数会控制该函数的行为结果。当然参数会有很多种写法,我们本章节会继续详细讲一讲。
def say_love_num(num):for i in range(0, num):print("我钟意你!")say_love_num(3)
你可能已经发现:如果不调用函数,函数是不会被执行的。
学习之前,我希望能够对于以下几个“专业术语”有所记忆。
定义:定义一个函数,可以理解为“创建一个函数”。
调用:我们刚才执行的“say_love() ”,就是调用的行为,指调用该“函数”。
传递:刚才第2个代码示例中,调用函数时,我们传入参数“3”,即将该参数传递给该函数,使它能够打印3遍内容。
** 假如你不太好记忆参数,我建议你可以这样理解,函数定义的参数可以叫做“形参”,调用函数传入的参数叫做“实参”。“实参”传递给该方法对应的“形参”,从而根据代码具体实现效果,输出或返回结果。
三、函数的参数。
刚才我们已经通过示例,了解到参数的一些作用,接下来,我们就详细说说参数都有哪些一定要知道的知识。
建议自己一边理解一边跟着练习一遍这些代码,运行看看结果。
位置参数
调用函数时根据函数定义的 参数位置 来 传递参数 。
注意:传递和定义的参数的顺序及个数必须一致
def user_info(name, age, sex):print(f"姓名:{name},年龄{age},性别{sex}")user_info("测试划水老师傅", 30, "男")
#运行结果:姓名:测试划水老师傅,年龄30,性别男
关键字参数
函数调用,通过 “键 = 值” 的形式指定。可以让函数更加清晰、容易使用,同时 不需要注意函数的顺序 。
def user_info(name, age, sex):print(f"姓名:{name},年龄{age},性别{sex}")user_info(age=30,name="测试划水老师傅",sex="男")
#运行结果:姓名:测试划水老师傅,年龄30,性别男
缺省参数
也叫默认参数,用于定义函数,为参数提供默认值,调用函数时,可以不传入该默认参数的值。
注意:所有位置参数必须写在默认参数前,包括函数定义和调用)
def user_info(name, age, sex="男"):print(f"姓名:{name},年龄{age},性别{sex}")user_info(age=30,name="测试划水老师傅")
#运行结果:姓名:测试划水老师傅,年龄30,性别男
不定长参数-位置参数
不定长参数也叫可变参数。
用于不确定调用时,会传入多少个参数(不传参数也可以)的场景。
此时,用包裹(packing)位置的参数,或者包裹关键字参数,来进行参数传递,会显得非常方便。
注意:
传进的所有参数都会被args变量收集,它会根据传进参数的位置合并为一个元组(tuple),args是元组类型,这就是包裹位置传递。
什么叫“元组”,我们不用关心,后续会讲到,目前你只需记住,函数的参数有这么一个写法即可。
def user_info(*args):print(args)user_info("测试划水老师傅", 30)
#运行结果:('测试划水老师傅', 30)
不定长参数-关键字参数
收集所有关键字参数,返回一个“字典”.
def user_info(**kwargs):print(kwargs)user_info(name = "测试划水老师傅", age = 30)
#运行结果:{'name': '测试划水老师傅', 'age': 30}
不定长参数“位置参数”、“关键字参数”,无论是包裹位置还是包裹关键字传递,都是一个组包的过程。
四、函数的返回值。
例如:我们去水果店买水果,付钱后,商家会给我们等价的苹果。
那么,在函数中,如果需要返回函数结果,需要使用return。
def shoopping():return "又红又大的苹果"goods = shoopping()
print(goods)
特点:
- 返回函数结果。
- return运行后,该函数结束,即return后编写代码不执行。(不信,你可以在return之后,在这个函数内些其他打印语句试试)
五、函数返回值的进阶玩法!
返回值作为参数传递
def test_A():str = "Python"return strdef test_B(book):print(book)result = test_A()
test_B(result)
#运行结果:Python
return 多个数据,并且定义返回的数据类型。
def test_A():str_1 = "Python"str_2 = "Java"return str_1, str_2def test_B():str_1 = "Python"str_2 = "Java"return (str_1, str_2)def test_C():str_1 = "Python"str_2 = "Java"return [str_1, str_2]def test_D():str_1 = "Python"str_2 = "Java"return {"key1":str_1,"key2":str_2}def test_E():str_1 = "Python"str_2 = "Java"return f"{str_1}、{str_2}"def print_return(book):print(book)result_1 = test_A()
print(result_1)
print(type(result_1))
result_2 = test_B()
print(result_2)
print(type(result_2))
result_3 = test_C()
print(result_3)
print(type(result_3))
result_4 = test_D()
print(result_4)
print(type(result_4))
result_5 = test_E()
print(result_5)
print(type(result_5))
#运行结果:
('Python', 'Java')
<class 'tuple'>
('Python', 'Java')
<class 'tuple'>
['Python', 'Java']
<class 'list'>
{'key1': 'Python', 'key2': 'Java'}
<class 'dict'>
Python、Java
<class 'str'>
函数的嵌套写法。指一个函数里面又调用另外一个函数。
def shoopping(book_name):"""这是一个介绍return的简单函数:return: "《Python核心编程》""""return "《Python核心编程》"def need_pay_num(book_name):if book_name == "《Python核心编程》":return "你需要支付60元"print(shoopping("《Python核心编程》"))
print(need_pay_num("《Python核心编程》"))
#运行结果:
《Python核心编程》
你需要支付60元
六、函数的说明文档。
我们如果需要将代码交给其他人,一般会这些生成函数文档,并且这也是一个好的代码注释习惯。```
def shoopping():"""这是一个介绍return的简单函数:return: "《Python核心编程》""""return "《Python核心编程》"help(shoopping)
# 运行结果:
Help on function shoopping in module __main__:
shoopping()这是一个介绍return的简单函数:return: "《Python核心编程》"
七、局部变量、全局变量和global关键字。
之前的学习,我们发现,一些变量会写在“函数内”、“函数外”。而细心的同学已经发现,这两者的变量作用域(可以使用的范围)是不一样的。
局部变量:是定义在函数体内的变量,只在函数体内部生效,如果在函数体外使用,则代码报错。
全局变量:指在函数体内、外都能生效的变量。
我们结合代码,来理解下。
# 全局变量
a = "测试划水老师傅"
def testA():print(a)testA()
print(a)
运行结果:
测试划水老师傅
测试划水老师傅
注意:
在函数体内部,临时保存数据,当函数体调用完成后,局部变量被销毁。
def testA():a = "测试划水老师傅"print(a)testA()
print(a)
运行结果:
测试划水老师傅
Traceback (most recent call last):File "E:\****\test.py", line 6, in <module>print(a)
NameError: name 'a' is not defined
如果另外一个函数内使用“局部变量”修改“全局变量”会有什么变化?
a = "测试划水老师傅"
def testA():print(a)def testB():a = "Python"print(a)
testA()
testB()
print(f'全局变量a = {a}')
运行结果:
测试划水老师傅
Python
全局变量a = 测试划水老师傅
利用global关键字,将函数体内的局部变量可以修改为全局变量。
a = "测试划水老师傅"
def testA():print(a)def testB():global aa = "Python"print(a)
testA()
testB()
print(f'全局变量a = {a}')
运行结果:
测试划水老师傅
Python
全局变量a = Python
八、异常处理。
截止目前为止,我们已经遇到很多报错或“异常”,一旦发生异常,程序将终于运行(崩溃)。
那我们一定不希望在实际工作过程中,发生程序终止的问题,而是希望程序能够将这些异常进行处理并继续执行。
比如下面这个代码,发生异常后,后面的程序不会在执行。
def input_print_num():num = int(input("输入内容:"))print(num)print("谢谢使用!")input_print_num()
我们之前都学过这个,如果此时,我输入的内容为非数字,就会发生下面这个错误。
输入内容:呵呵
Traceback (most recent call last):File "E:\code\learning_python_basis\Lesson_code_4\异常处理.py", line 6, in <module>input_print_num()File "E:\code\learning_python_basis\Lesson_code_4\异常处理.py", line 2, in input_print_numnum = int(input("输入内容:"))^^^^^^^^^^^^^^^^^^^
ValueError: invalid literal for int() with base 10: '呵呵'
发生报错后,程序停止运行,函数内之后的语句不在执行。
接下来,我们试试加上异常处理,看会有什么结果。
def input_print_num():try:num = int(input("输入内容:"))print(num)except ValueError:print("输入错误")print("谢谢使用!")input_print_num()
运行结果:
输入内容:按时
输入错误
谢谢使用!
我们发现,程序没有崩溃,会将捕获的错误,按照我们定义的内容进行输出,之后的程序可以继续运行。
练习题
试试将我们上一节课的练习题,运用函数的思想,进行拆解和编写,你会如何去做呢?可以来老师傅的星球讨论。