Die basis -8 funktionen
一、函数的简介
1.函数的特点:
- 函数是一个对象
- 函数用来保存一些可执行的代码,并且可以在需要的时候,对这些语句进行多次调用
- 函数中保存的代码不会立即执行,需要调用才会执行。
2.函数的创建:
- 语法:
def 函数名():
代码块
函数名() - 例如
def fn()
代码块
fn() - 注:fn是函数名,也是函数的对象。
- 注:fn()是调用函数(本身的个数就是函数调用的次数)。
- 注:函数内部的代码块必须缩进。
3.函数的命名规范:
函数名称应该符合标识符的命名规则:
- 可以有字母下划线和数字组成
- 不能以数字开头
- 不能和关键字崇明
二、函数的参数
- 形参(形式参数):定义形参就相当于在函数内部声明了变量。但是并不是赋值。
- 实参(实际参数):指定了形参,那么在调用函数时必须传递实参,实参将会赋值给对应的形参,简单来说有几个形参酒哟月几个实参。
- 作用:函数的参数可以增加函数的通用性,针对相同的数据处理逻辑,能够适应更多的数据。
1 .在函数内部吧参数当作变量来熟用,进行需要的数据处理。
2 .在函数调用时,按照函数定义的参数顺序,把希望在函数内处理的数据,通过参数处理。 - 例如:
def fn(a, b):
print(a + b)
fn(1,2)
fn(12345,7454854)
打印输出:
/usr/local/bin/python3.8 /Users/wangjiaxin/PycharmProjects/wangjiaxin/Python-Cheney老师基础讲解/第八讲/3--函数的参数.py
3
7467199
Process finished with exit code 0
三、参数的传递方式
3.1 参数指定默认值
- 定义形参时,可以为形参指定默认值。指定默认值后,如果用户传递了参数则默认值无效。如果用户未传递参数,则默认值有效。
- 例如:
def fn(a, b, c=20):
print('a =', a)
print('b =', b)
print('c =', c)
fn(1, 2, 3)
def fn(a, b, c=20):
print('a =', a)
print('b =', b)
print('c =', c)
fn(1, 2)
打印输出:
/usr/local/bin/python3.8 /Users/wangjiaxin/PycharmProjects/wangjiaxin/Python-Cheney老师基础讲解/第八讲/4--参数的传递方式.py
a = 1
b = 2
c = 3
a = 1
b = 2
c = 20
Process finished with exit code 0
3.2 位置传参
- 位置参数:位置参数就是将对应位置的实参赋值给对应位置的形参。
- 例如:
def fn(a, b, c):
print('a =', a)
print('b =', b)
print('c =', c)
fn(1, 2, 3)
打印输出:
a = 1
b = 2
c = 3
3.3 关键字传参
- 关键字传参:可以不按照形参定义的顺序去传递,而根据参数名进行传递。
- 例如:
def fn(a, b, c):
print('a =', a)
print('b =', b)
print('c =', c)
fn(b=20,a=2,c=3)
打印输出:
/usr/local/bin/python3.8 /Users/wangjiaxin/PycharmProjects/wangjiaxin/Python-Cheney老师基础讲解/第八讲/4--参数的传递方式.py
a = 2
b = 20
c = 3
Process finished with exit code 0
3.4 混合传参
- 混合使用位置参数和关键字参数的时候必须将位置参数写到关键字参数之前。
- 例如:
def fn(a, b, c):
print('a =', a)
print('b =', b)
print('c =', c)
fn(20,b=2,c=3)
打印输出:
/usr/local/bin/python3.8 /Users/wangjiaxin/PycharmProjects/wangjiaxin/Python-Cheney老师基础讲解/第八讲/4--参数的传递方式.py
a = 20
b = 2
c = 3
Process finished with exit code 0
四、参数的类型
- 实参可以传递任意类型的参数
- 例如:
- 1 .int整数类型:
def fn(a):
print('a =', a)
fn(1)
- 2 .dict列表类型
def fn(a):
print('a =', a)
a = [1,2,3]
fn(a)
- 3 .布尔类型
def fn(a):
print('a =', a)
a = True
fn(a)
- 4 .字典类型
def fn(a):
print('a =', a)
a = {'1', 1}
fn(a)
- 5 .递归函数
- 递归函数:递归函数是指函数调用自身函数
def fn(i):
if i == 1:
print('你好,世界!!!')
else:
print('看来世界是失败的!!')
return fn(i-1)
fn(3)
打印输出
看来世界是失败的!!
看来世界是失败的!!
你好,世界!!!
这是一个简单的递归函数,我将3传参给i,但是3不等于1,就继续减1运行,打印输出就是
看来世界是失败的!!
看来世界是失败的!!
你好,世界!!!
这样的输出文件。
- 递归函数的优点:首先是定义简单,逻辑清晰。理论上所有的递归函数都可以写成循环的方式,但是循环函数的逻辑不如递归清晰。
- 注意事项:
- 防止栈溢出。
(栈:可以称为堆栈,是一种容器,可以存入数据元素、访问元素、删除元素,它的特点是只能允许在容器的一端(称为栈顶端指标,英语:top)进行加入数据(英语:push)和输出数据(英语:pop)的运算。没有位置概念,保证任何时候可以访问、删除的元素都是此前最后存入的元素,确定了一种默认的访问顺序)在计算机中,函数的调用时通过栈(英语:stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,随意,递归次数过多,会导致栈的溢出。
删除线:是栈的基本概念。
- 防止栈溢出。
- 关于递归函数的结论:递归函数逻辑简单清晰,但是过深的调用会导致栈溢出。
五、不定长参数
- 定义函数时,可以在形参前面加一个*(通配符),这样这个形参可以获取到所有的实参,他会将所有的实参保存在一个元祖内。
- 例如:
- 使用*接受不定长参数,a对应的数据时一个元组(是args)
def fn(*a):
print('a =', a)
fn(1,2,3)
流程:
- ( * a)可以和其他阐述配合适应,但是需要放在后面,并且带号的有且只有一个,可以和其他参数配合适应
- *只能接受位置参数,不能接受关键字参数
- 例如:
def fn(*args,b):
print('a = ', args)
print(b)
fn(1, 2, 3)# ---- 函数报错
打印输出:
Traceback (most recent call last):
File "/Users/wangjiaxin/PycharmProjects/wangjiaxin/Python-Cheney老师基础讲解/第八讲/6--不定长参数.py", line 26, in <module>
fn(1, 2, 3)# ---- 函数报错
TypeError: fn() missing 1 required keyword-only argument: 'b'
翻译:
文件“ / Users / wangjiaxin / PycharmProjects / wangjiaxin / Python-Cheney Old Man基本解决方案/第八讲/ 6-无限个Long References.py”,第26行,在<模块>中
fn(1、2、3)#----
TypeError:fn()缺少1个仅关键字必需的参数:‘b’
- 形参**可以接受其他关键字参数,它会将这些参数统一保存到字典中。字典的key就是参数的名字,字典的value就是参数的值
- 例如:
def fn(**kwargs):
print('a = ', kwargs)
fn(a=1, b=2, c=3)
打印输出:
a = {'a': 1, 'b': 2, 'c': 3}
输出的是一个名为a的字典。
- 形参**有切只有一个并且必须放在最后面。
- 例如:组合参数
def fn(*args,**kwargs):
print('a = ', kwargs)
print('a = ', args)
fn( 1, 2 ,3 , a=1, b=2, c=3)
打印输出:
a = {'a': 1, 'b': 2, 'c': 3}
a = (1, 2, 3)
生成一个字典,一个元组。
六、参数(元组与字典)的拆包
传递实参时,也可以在序列类型的参数前面添加星号,这样他会自动的将序列中的元素依次作为参数传递。
要求序列中的元素个个数必须和形参的个数一致。
在调用待用多值参数的函数时,如果希望:
- 将一个元组的变量,直接传递给args
- 将一个字典的变量,直接传递给kwargs
使用拆包可以简化参数的传递。拆包方式:
- 在元组变量前,增加一个*
- 在字典变量前,增加两个*
1 .元组的拆包
def fn(a,b,c):
print('a = ', a)
print('b = ', b)
print('c = ', c)
tuple = (1, 2, 3)
fn(tuple[0],tuple[1],tuple[2])
fn(*tuple)
打印输出:
a = 1
b = 2
c = 3
a = 1
b = 2
c = 3
上述事例为元组拆包的两种方式
2 .字典的拆包:字典的拆包时关键字传参,需要用到两个* 来完成
def fn(a,b,c):
print('a = ', a)
print('b = ', b)
print('c = ', c)
d = {'a' : 1,'b' : 2, 'c' : 3}
fn(**d)
打印输出:
a = 1
b = 2
c = 3
七、拓展–可变类型与不可变类型
可变类型:list(列表)、dict(字典)、set(集合)—value改变,而内存id不会变。
不可变类型:str(字符串)、tuple(元组)、数字(int、bool、float、、)—value改变,而内存id会变。
- 意义:
1 .可变与不可变是指,在对象本身进行操作时,引用所指向的地址里的内容是否发生了变化。
2 .比如在函数中局部变量本身发生变化,同名的全局变量是否发生变化。 - 可变类型:列表
示例一:
list = [1,2,3,4]
print(id(list))
list[0] = 10
print(id(list))
打印输出:
140197516361984
140197516361984
结果是当列表内的元素出现变化时,id()为发生变化。
- 不可变类型:字符串
示例二:
str1 = 'abcd'
print(id(str1))
r = str1.upper() # 将字符串的内容进行大写返回
print(id(r))
打印输出:
140197517855856
140197517856432
结果是当字符串内部数据发生变化时,id()也发生变化。
- 使用注意:在调用函数时,函数内部的局部变量名和全局变量名一致时,要注意可变类型变量的值的变化。
演示1:
a = [1,2,3]
def fn(num):
num += num
print(num)
fn(a)
print(a)
打印输出:
[1, 2, 3, 1, 2, 3]
[1, 2, 3, 1, 2, 3]
演示二:
a = [1,2,3]
def fn(num):
num = num + num
print(num)
fn(a)
print(a)
打印输出:
[1, 2, 3, 1, 2, 3]
[1, 2, 3]
课后作业:
作业一:
'''
打印名片程序:输入姓名、电话号码、性别,最后打印出名片
1.控制姓名长度为6-20
2。电话号码长度为11
3.性别只能允许输入男或女
4.每一样信息不能为空
'''
代码如下:
# 分析:
# 1.定义一个函数,将需要输入的形参利用{}.format(name,gender,telephone)分别抓取至{}占位符内
def fn(name,gender,telephone):
print('''
请输入姓名:{}
性别:{}
电话号码:{}'''.format(name,gender,telephone))
# 2.输入姓名,长度为6-20,不符合则重新输入
while True:
name = input('请输入姓名:')
if 6 <= len(name) <=20:
break
else:
print('你是俄罗斯人吗?换个短一点的名字')
# 3.输入性别,只有男或女,不符合重新输入
while True:
gender = input('请输入性别:')
if gender == '男' or gender == '女':
break
else:
print('你是哪朝哪代的太监?还是不男不女?')
# 4.输入电话号码,长度为11位,不符合重新输入
while True:
telephone = input('请输入电话号码:')
if len(telephone) == 11:
break
else:
print('我原谅你刚从国外回来,请输入一个中国的手机号,谢谢🙏')
# 5.调用自定义函数fn(name,gender,telephone)
fn(name,gender,telephone)
打印输出结果:
请输入姓名:王佳欣
你是俄罗斯人吗?换个短一点的名字
请输入姓名:wangjiaxin
请输入性别:男
请输入电话号码:15840039263
请输入姓名:wangjiaxin
性别:男
电话号码:15840039263
总结:
1 .定义一个自定义函数,设定好形参于实参,并通过{}.format()将需要正确输入的实参分别抓取进{}内。
2 .通过三次while Ture:循环独立的使用input()函数、if判断语句,对条件进行判断,条件通过,break停止当前循环。进下一层循环,同上。直至输入正确得出所有正确结果,enter打印输出名片。
作业二:
'''
使用函数求前20个斐波那契数列。斐波那契数列:1,1,2,3,5,8,13,21。。。。。即:起始两项均为1,伺候的祥分别是前两项的和
'''
代码如下:
- 方法一:
# 1. 建立一个空列表
list1 = []
# 自定义函数fn():
def fn():
# 根据题义:求前20个数列,利用for i in range():循环遍历20次
for i in range(20):
# 如果i=0或者i=1,则祥列表内添加元素1
if i == 1 or i == 0:
list1.append(1)
# 反之:则像列表list1中添加代入的列表计算公式list1[i-2]+list1[i-1]
else:
list1.append(list1[i-2]+list1[i-1])
print(list1)
fn()
- 方法二:(来自csdn大神(瑞吉儿)的便捷方法)
# 建立一个列表,并在列表内添加元素1,1
list1 = [1,1]
# 自定义函数fn():
def fn():
# 根据题义:求前20个数列,利用for i in range():循环遍历20次
while len(list1) < 20:
list1.append(list1[-1]+list1[-2])
print(list1)
fn()
两种方法打印结果:
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
总结:
1 .作业二难点在于列表内元素的计算,通过上述拓展可变类型与不可变类型可知,列表为可变对象,即:value值改变,其自身id位置不变。
2 .通过for I in range():遍历循环0,20,因为需要求前20个数列所以写0,20.遍历20次,以完成20次循环。
3 .通过if-else:判断语句完成对列表内元素的计算判断
4 .输出打印
作业三:
'''
编写一段代码,定义一个函数求1-100之间的所有整数的和,并调用函数打印出结果
'''
代码如下:
- 方法一:
def fn():
n = 0
for i in range(1, 101):
n = n + i
print(n)
fn()
- 方法二:
def fn(i):
n = 0
while i < 100:
i += 1
# print(i)
n = n + i
print(n)
fn(0)
两种方法打印结果:
5050
5050
总结:
1 . 第一种方法是利用for i in range(1,101),遍历出1–100的所有整数。
2 .再通过基本的赋值运算得出结果。
3 . 第二种方法是利用while循环来列出1–100的所有整数
4 .再通过基本的赋值运算得出结果。