Python
- Python
- 一、补充循环结构
- for循环:
- 二、函数
- 1、函数(function)
- 2、调用函数:
- 3、函数的分类:
- 4、局部变量和全局变量:
- 5、函数在内存中调用问题
- 6、值传递和引用传递:
- 7、函数的参数
- 8、函数传递
- 9、匿名函数以及lambda表达式
- 10、偏函数
- 三、递归
- 递归的内存分析以及优缺点
- 四、容器
- 五、作业:
- 作业1
- 作业2:
- 作业3:
- 作业:
- 作业5:
- 作业6:
- 作业7:
- 作业8:
- 作业9:
- 作业10:
- 作业11:
- 作业12:
- 作业13:
- 作业14:
Python
一、补充循环结构
for循环:
由于while只能通过下标进行循环,不过有些容器是没有下标的,不能用while循环。
所以设计出来了for循环,Python中的for本质是用来迭代容器中的每一个元素的!!!
而不是在C,Java理解的那个循环。
列表[]:和数组有点像,不过更像是数据结构中的list。
里面可以包含多个元素。
我们来看下具有下标的:
>>> ["1","2","3"]
['1', '2', '3']
>>> users = ['1','2','3']
>>> users
['1', '2', '3']
>>> users[1]
'2'
>>> users[0]
'1'
>>> users[2]
'3'
首先我们在users中存储了三个元素。
接下来我们使用循环将其进行输出:
>>> len(users)
3
>>> i = 0
>>> while i < len(users):
... print(users[i])
... i += 1
...
1
2
3
>>>
此时是具有下标的情况,而我们往往在之后不知道元素具体的位置,我们又该怎么办呢?比如说哈希表。
这时我们引入了for循环,当然for循环我们可以在有序中使用也可以在无序中使用。
简单来演示下for循环的使用方法:
for 临时变量 in(所属运算符) 容器 :print(临时变量) #每一个迭代出来的元素
例如:
>>> for user in users:
... print(user)
...
1
2
3
>>>
range全局函数:
range(nujm)
** #[0,num)区间内的所有整数**
我们实际操作来观察下:
>>> range(10)
range(0, 10)
>>> for i in range(10):
... print(i)
...
0
1
2
3
4
5
6
7
8
9
>>>
range(start , end)
#[start,end)区间内的所有整数
比如说我们要求10到20之间的数的和包含10以及20
实现代码:
>>> s = 0
>>> for i in range(10,21):
... s += i
...
>>> s
165
>>>
那如果说我们要求10到20包含10但不包含20:
>>> s = 0
>>> for i in range(10,20):
... s += i
...
>>> s
145
>>>
这个就是关于两个参数。
那如果我们要三个参数的,比如1,3,5······
range(start,end,step) #默认步长是1,但是可以通关第三个参数修改步长那个。
比如我们接下来求0到100的偶数:
>>> for x in range(0,101,2):
... print(x)
...
0
2
4
6
8
10
12
14
16
18
20
22
24
26
28
30
32
34
36
38
40
42
44
46
48
50
52
54
56
58
60
62
64
66
68
70
72
74
76
78
80
82
84
86
88
90
92
94
96
98
100
>>>
步长可以填负数,那便是自减。
比如我们求1到100的和:
方法一:
>>> s = 0
>>> for i in range(101):
... s += i
...
>>> s
5050
方法二:
>>> s = 0
>>> for i in range(100,0,-1):
... s += i
...
>>> s
5050
>>>
接下来我们使用for循环进行打印:
题目1:
*
**
***
****
*****
实现代码:
layer = int(input("请输入您要打印的层数"))for i in range(1,layer + 1):for j in range(i):print("*",end = "")print()
输出结果:
D:\soft\pythonworkplace>test.py
请输入您要打印的层数5
*
**
***
****
*****D:\soft\pythonworkplace>
题目2:
*
***
*****
*******
*********
实现代码:
layer = int(input("请输入您要打印的层数:"))for i in range(layer):for j in range(2 * i + 1):print("*",end = "")print()
输出结果:
D:\soft\pythonworkplace>test.py
请输入您要打印的层数:5
*
***
*****
*******
*********D:\soft\pythonworkplace>
题目3:
**********
*****
实现代码:
layer = int(input("请输入您要打印的层数:"))for i in range(1,layer + 1):space_name = layer - ifor j in range(space_name):print(" ",end = "")for j in range(i):print("*",end = "")print()
输出结果:
D:\soft\pythonworkplace>test.py
请输入您要打印的层数:5**********
*****D:\soft\pythonworkplace>
这道题同样可以进行简化代码:
layer = int(input("请输入您要打印的层数:"))
for i in range(1,layer + 1):print(" " * (layer - i),end = "")print("*" * i)
输出结果:
D:\soft\pythonworkplace>test.py
请输入您要打印的层数:6***************
******D:\soft\pythonworkplace>
题目4:
* *** *****
*******
实现代码:
layer = int(input("请输入您要打印的层数:"))for i in range(1, layer + 1):for j in range(layer - i):print(" ",end = "")for j in range(2 * i - 1):print("*",end = "")print()
输出结果
D:\soft\pythonworkplace>test.py
请输入您要打印的层数:5****************
*********D:\soft\pythonworkplace>
题目5:
************ ****
实现代码:
layer = int(input("请输入您要打印的层数:"))for i in range(layer,0,-1):for j in range(layer - i):print(" ",end = "")for j in range(2 * i - 1):print("*",end = "")print()
输出结果:
D:\soft\pythonworkplace>test.py
请输入您要打印的层数:5
*************************D:\soft\pythonworkplace>
题目6:
****************
*************************
实现代码:
layer = int(input("请输入您要打印的层数:"))while layer % 2 == 0:layer = int(input("请输入奇数行"))
for i in range(0,layer // 2 + 1):print(" " * (layer - i),end = "")print("*" * (2 * i + 1))
for i in range(layer // 2,0,-1):print(" " * (layer - i + 1),end = "")print("*" * (2 * i - 1))
输出结果:
D:\soft\pythonworkplace>test.py
请输入您要打印的层数:11*************************************************************D:\soft\pythonworkplace>
题目7:
** ** *
* ** ** **
实现代码:
layer = int(input("请输入您要打印的层数:"))while layer % 2 == 0:layer = int(input("请输入奇数行"))
for i in range(0,layer // 2 + 2):print(" " * (layer - i),end = "")for j in range(2 * i + 2):if j == 0 or j == 2 * i:print("*",end = "")else:print(" ",end = "")print()
for i in range(layer // 2,-1,-1):print(" " * (layer - i),end = "")for j in range(2 * i + 1):if j == 0 or j == 2 * i:print("*",end = "")else:print(" ",end = "")print()
输出结果:
D:\soft\pythonworkplace>test.py
请输入您要打印的层数:11** ** ** ** ** ** ** ** ** ** ** **D:\soft\pythonworkplace>
题目8:
***** * ** * ** * ** * *************** * ** * ** * ** * *****
实现代码:
layer = int(input("请输入您要打印的层数:"))while layer % 2 == 0:layer = int(input("请输入奇数行"))
for i in range(0,layer // 2 + 2):print(" " * (layer - i),end = "")for j in range(2 * i + 1):if j == 0 or j == 2 * i or j == i or i ==layer // 2 + 1:print("*",end = "")else:print(" ",end = "")print()
for i in range(layer // 2,-1,-1):print(" " * (layer - i),end = "")for j in range(2 * i + 1):if j == 0 or j == 2 * i or j == i:print("*",end = "")else:print(" ",end = "")print()
输出结果:
D:\soft\pythonworkplace>test.py
请输入您要打印的层数:11***** * ** * ** * ** * *************** * ** * ** * ** * *****D:\soft\pythonworkplace>
二、函数
1、函数(function)
1.1 什么叫做函数?
编程看来,函数其本质就是一个功能代码的集合。
函数本质就是现实中行为动作的代名词;
具有名称的功能代码的集合
1.2 python中函数如何定义:
使用关键字def
【该关键字就是用来定义函数的】
defined function
def 函数名称([参数列表...]):# 函数体 由一行或者多行代码组成# [return 返回值]
1.3 案例:
在控制上输出三句你好
实现代码:
# 实现一个函数,在控制台上输出你好
def say_hello():print("你好")print("你好")print("你好")
输出结果:
D:\soft\pythonworkplace>test.pyD:\soft\pythonworkplace>
1.4 这里我们又为什么没有输出结果呢?
这里我们可以把函数理解为功能,这里它的功能也就是输出三句你好;然则你也可以有很多的功能;但是,功能的实现我们肯定是建立在需求之上的, 也就是我们构建了多个函数,有很多的功能,而这些功能呢?我们肯定不是每时每刻都要用到,所有函数本身是不进行执行的,同时,我们也进行学习了函数本身的功能也就是实现功能的复用。
所以当函数定义完成之后我们就要进行调用函数。
2、调用函数:
[返回值 = ]函数名称([参数列表])
C:\Users\lenovo>python
Python 3.11.3 (tags/v3.11.3:f3909b8, Apr 4 2023, 23:49:59) [MSC v.1934 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> help(print)
Help on built-in function print in module builtins:print(*args, sep=' ', end='\n', file=None, flush=False)Prints the values to a stream, or to sys.stdout by default.sepstring inserted between values, default a space.endstring appended after the last value, default a newline.filea file-like object (stream); defaults to the current sys.stdout.flushwhether to forcibly flush the stream.>>> print()
所以上一个案例的完整代码:
# 实现一个函数,在控制台上输出你好
def say_hello():print("你好")print("你好")print("你好")# 调用函数
say_hello()
此时我们来看输出结果:
D:\soft\pythonworkplace>test.py
你好
你好
你好D:\soft\pythonworkplace>
好的,这里我们改变案例要求,我想要输出别人的基本信息,而print自己的基本信息不能进行修改;
所以此时我们可以进行改变下:
# 实现一个函数,在控制台上输出你好
def say_hello(name,age,address,gender):print(f"我叫{name}")print(f"我今年{age}岁")print(f"我是一个来自{address}的{gender}")# 调用函数
say_hello()
输出结果:
D:\soft\pythonworkplace>test.py
Traceback (most recent call last):File "D:\soft\pythonworkplace\test.py", line 573, in <module>say_hello()
TypeError: say_hello() missing 4 required positional arguments: 'name', 'age', 'address', and 'gender'D:\soft\pythonworkplace>
这里我们的很显然的可以看出我们并没有给他们传name,age,address,gender
这四个值,所以:
# 实现一个函数,在控制台上输出你好
def say_hello(name,age,address,gender):print(f"我叫{name}")print(f"我今年{age}岁")print(f"我是一个来自{address}的{gender}")# 调用函数
say_hello("1",16,"陕西西安","男生")
say_hello("2",17,"陕西渭南","女生")
say_hello("3",18,"陕西延安","女生")
输出结果:
D:\soft\pythonworkplace>test.py
我叫1
我今年16岁
我是一个来自陕西西安的男生
我叫2
我今年17岁
我是一个来自陕西渭南的女生
我叫3
我今年18岁
我是一个来自陕西延安的女生D:\soft\pythonworkplace>
3、函数的分类:
这里上面案例进行阐述了有参数以及没有参数的案例。
所以,下面我们来一起看下有返回值的函数:
案例要求:输出x和y的和
实现代码:
def add(x,y):return x + yadd(10,20)
这里我们可以看到输出结果:
D:\soft\pythonworkplace>test.pyD:\soft\pythonworkplace>
输出结果并没有,这又是什么原因?
我们首先来测试函数是否进行执行了:
实现代码:
def add(x,y):print("函数执行了吗")return x + yadd(10,20)
输出结果:
D:\soft\pythonworkplace>test.py
函数执行了吗D:\soft\pythonworkplace>
这里我们可以看到函数是执行了的。
这里其实已经是返回了一个结果,我们只是没有进行接收这个值,所以:
def add(x,y):return x + yres = add(10,20)
print(res)
输出结果:
D:\soft\pythonworkplace>test.py
30D:\soft\pythonworkplace>
下面我们来看下函数的分类。
- 以函数是否存在返回值:
有返回值的函数 return关键字 调用后需要接受返回值
无返回值的函数 没有return关键字 返回值为None - 以函数是否存在参数:
有参数函数
无参数函数
4、局部变量和全局变量:
1、局部变量(local variable
):又叫做本地变量,定义在函数内部的变量
局部变量只能在当前定义的函数内部有效
2、全局变量(global variable
):直接定义在模块中的变量,叫做全局变量
在python中,函数内部不允许修改全局变量!!!!
3、实际练习:
# 全局变量
name = "张三"
age = 16def work_1(msg,show):# a就是一个局部变量a = 20# 全局变量可以直接在函数内部访问print(name)print(age)print(a)a += 10print(a)work_1("哦","聊天止于哦哦")
这里我们来猜想下输出结果:
D:\soft\pythonworkplace>test.py
张三
16
20
30D:\soft\pythonworkplace>
好,那么我们此时进行分步访问测试:
首先我们进行全局变量的访问:
name = "张三"
age = 16def work_1(msg,show):a = 20print(name)print(age)print(a)a += 10print(a)work_1("哦","聊天止于哦哦")print(name)
print(age)
输出结果:
D:\soft\pythonworkplace>test.py
张三
16
20
30
张三
16D:\soft\pythonworkplace>
我们可以看到我们可以在外界正常访问到全局变量;
接下来我们来访问a的值:
name = "张三"
age = 16def work_1(msg,show):a = 20print(name)print(age)print(a)a += 10print(a)work_1("哦","聊天止于哦哦")print(name)
print(age)
print(a)
输出结果:
D:\soft\pythonworkplace>test.py
张三
16
20
30
张三
16
Traceback (most recent call last):File "D:\soft\pythonworkplace\test.py", line 600, in <module>print(a)^
NameError: name 'a' is not definedD:\soft\pythonworkplace>
我们可以看到这里只有a是没有正常访问到的,报错了。
变量a没有被定义。
下面我们接着改变案例的要求,这里要输出张三长了一岁的年龄:
name = "张三"
age = 16def work_1(msg,show):a = 20print(name)print(age)print(a)a += 10print(a)age += 1print(age)work_1("哦","聊天止于哦哦")print(name)
print(age)
# print(a)
输出结果:
D:\soft\pythonworkplace>test.py
张三
Traceback (most recent call last):File "D:\soft\pythonworkplace\test.py", line 599, in <module>work_1("哦","聊天止于哦哦")File "D:\soft\pythonworkplace\test.py", line 590, in work_1print(age)^^^
UnboundLocalError: cannot access local variable 'age' where it is not associated with a valueD:\soft\pythonworkplace>
我们可以看到这里报错了,又是什么原因呢?
这里它的意思是找不到局部变量age。
这又是什么原因呢?
正常情况,python拒绝在函数中修改全局变量,但是考虑到特殊情况下的需求,python中如果要修改全局变量,需要提前声明!!!!
如果说我们此时加上一个局部变量age:
name = "张三"
age = 16def work_1(msg,show):age = 1a = 20print(name)print(age)print(a)a += 10print(a)age += 1print(age)work_1("哦","聊天止于哦哦")print(name)
print(age)
# print(a)
输出结果:
D:\soft\pythonworkplace>test.py
张三
1
20
30
2
张三
16D:\soft\pythonworkplace>
我们可以看到内部输出的age最后加了1,而最终输出的age值依然为我们定义的值16。
下面这个便是全局变量确实需要修改的时候,我们则需要在其使用内部加上声明global:
关键字 global 来声明
name = "张三"
age = 16def work_1(msg,show):global agea = 20print(name)print(age)print(a)a += 10print(a)age += 1print(age)work_1("哦","聊天止于哦哦")print(name)
print(age)
# print(a)
输出结果:
D:\soft\pythonworkplace>test.py
张三
16
20
30
17
张三
17D:\soft\pythonworkplace>
5、函数在内存中调用问题
a = 10def test():b = 230print("hello")test()
那么我们来猜想下电脑执行代码的过程:
内存是一个缓冲设备;
这里我们在第一节课讲到过;
内存中存在着堆以及栈,对象都是放在堆中,栈是一种线性结果,先进后出FILO以及后进先出LIFO。
与栈相对立的为队列:先进先出,后进后出。
程序为什么要建立这种结构?
首先我们来思考下我们创建执行栈而不创建执行队列?
假如我们有以下一串代码?
a = 10
b = a + 10
如果说我们创建的是队列,那么我们最终想要访问b的值,而a已经出去了,则访问不到了;栈的话则不一样,它会在执行b = a + 10之前将a = 10存进去。
然而当我们将所有的都往里面放,内存则会被撑爆了。也从而导致内存溢出。
下面我们接着分析;
在python中,函数本质也是一种对象!!!!!
对象则会存在堆里面,栈空间有限。
我们将函数的地址存在了栈中,和C中指针有点像。
程序调用的:本质就是将函数临时压入执行栈!!!
也就是我们将test函数压入栈中进行执行,当执行完最后一行代码就会立即进行弹栈操作,以避免长时间占用内存。
这里我们就可以理解为什么局部变量不能够被外面访问到,因为函数执行完毕立即弹栈,栈已经不存在局部变量的值了。
6、值传递和引用传递:
- 值传递:变量之间,数值的传递,这种传递相当于变量赋值
- 引用传递:传递的地址(指针),对象,引用
形参是局部变量
我们来看下面这串代码:
def change(a,b):a += 10b += 30print(a,b)x = 100
y = 200
print(x,y)
change(x,y)
print(x,y)
下面我们来看输出结果:
D:\soft\pythonworkplace>test.py
100 200
110 230
100 200D:\soft\pythonworkplace>
这里也很好理解。
a和b这里只是局部变量,我们只进行了将x以及y的值分别赋予给了a以及b,也就是值传递,函数内部修改不会影响x以及y因为这是一个值传递。
下面我们来看下一串代码:
def change(a,b):a += 10b += 30print(a,b)x = 100
y = 200
print(x,y)
change(x,y)
print(x,y)def add(nums):nums.append(100)nums.append(200)print(nums)ages = [10,20,30]
print(ages)
add(ages)
print(ages)
输出结果:
D:\soft\pythonworkplace>test.py
100 200
110 230
100 200
[10, 20, 30]
[10, 20, 30, 100, 200]
[10, 20, 30, 100, 200]D:\soft\pythonworkplace>
这里我们可以看到,我们最终将100以及200存了进去。
这又是什么原因呢?
ages在这里也就是对象,对象我们都是存放在堆中的,堆中地址则存在了栈中,而这里add则传递的是地址,也就相当于nums变量拿到的是ages的存放堆中的地址,也就相当于指向了这一变量,而这里ages则将值存了进去,那么nums也会将100以及200存到这个地址中去。
7、函数的参数
# (默认值、可变、关键字参数)
def func_name([arge...])# 函数体# [return 返回值]
练习,求圆的周长以及面积。
在这之前,我们首先知道一个东西:帮助文档:
>>> help(print)
Help on built-in function print in module builtins:print(*args, sep=' ', end='\n', file=None, flush=False)Prints the values to a stream, or to sys.stdout by default.sepstring inserted between values, default a space.endstring appended after the last value, default a newline.filea file-like object (stream); defaults to the current sys.stdout.flushwhether to forcibly flush the stream.>>>
我们一般给函数进行标注注释一般在函数的上方,而python不一样,这里必须在函数定义下面的第一行,比如:
def get_circle_area():"""求圆的面积"""passprint(help(get_circle_area))
输出结果:
D:\soft\pythonworkplace>test.py
Help on function get_circle_area in module __main__:get_circle_area()求圆的面积NoneD:\soft\pythonworkplace>
这里none代表返回值为空。
而这里我们打印了所有,我们如果想要打印帮助文档:
def get_circle_area():"""求圆的面积"""passprint(get_circle_area.__doc__)
输出结果:
D:\soft\pythonworkplace>test.py求圆的面积D:\soft\pythonworkplace>
好,我们接着看求圆的面积:
def get_circle_area(r,PI):"""求圆的面积"""return r * r * PIr1 = float(input("请输入圆的半径:"))print(get_circle_area(r1,3.14))
输出结果:
D:\soft\pythonworkplace>test.py
请输入圆的半径:2
12.56D:\soft\pythonworkplace>test.py
请输入圆的半径:3
28.26D:\soft\pythonworkplace>
默认值参数:
如果函数中的某个或者某些参数,在调用时大多数情况下,是一个固定值。
为了调用方便,可以设定默认值。
默认值参数一定要写在普通值参数之后,否则会报错。
如果一个值在大多数情况下取一个值,我们可以默认给他一个值,比如这里PI大多数情况下使用3.14,则:
def get_circle_area(r,PI=3.14):"""求圆的面积"""return r * r * PIr1 = float(input("请输入圆的半径:"))print(get_circle_area(r1))
输出结果:
D:\soft\pythonworkplace>test.py
请输入圆的半径:4
50.24D:\soft\pythonworkplace>
当然,如果我给了PI另一个值,那么他肯定是使用给定值,如果没有才采用默认值:
def get_circle_area(r,PI=3.14):"""求圆的面积"""return r * r * PIr1 = float(input("请输入圆的半径:"))print(get_circle_area(r1))
print(get_circle_area(r1,3.1415926))
输出结果:
D:\soft\pythonworkplace>test.py
请输入圆的半径:3
28.26
28.2743334D:\soft\pythonworkplace>
可变参数:
*变量 这种形式定义的,注意:不是C语言中指针
它主要用来存储额外的参数!!!!,会将参数封装到元组中
依然是上一个案例,我们如果说想要进行加入别的功能,我们可以进行加入函数,当然,python中也可以加入可变参数。加上*arges不影响原来的代码,可以给他不进行传值。
def test(x,y,*args):print(x + y)test(2,5)
test(2,3,4,5,6,7)
输出结果:
D:\soft\pythonworkplace>test.py
7
5D:\soft\pythonworkplace>
这里我们可以看到,我们给它进行多传几个值依然不会影响原来的代码,但是,最终执行的功能我们可以看到进行多个输入,它只传前面两个值,,从而输出了5.
而这里我们加入arges又有什么用呢?
def test(x,y,*args):print(args)print(x + y)test(2,5)
test(2,3,4,5,6,7)
输出结果:
D:\soft\pythonworkplace>test.py
()
7
(4, 5, 6, 7)
5D:\soft\pythonworkplace>
这里我们可以看到里面存进了4567,也就是你传了多余的参数他会把这些存进去。扩展了程序的功能也不影响原有的代码。
def test(x,y,*args):if len(args) > 0:print(args[0])print(x + y)test(2,5)
test(2,3,4,5,6,7)
输出结果:
D:\soft\pythonworkplace>test.py
7
4
5D:\soft\pythonworkplace>
所以,我们可以看下print函数:
>>> help(print)
Help on built-in function print in module builtins:print(*args, sep=' ', end='\n', file=None, flush=False)Prints the values to a stream, or to sys.stdout by default.sepstring inserted between values, default a space.endstring appended after the last value, default a newline.filea file-like object (stream); defaults to the current sys.stdout.flushwhether to forcibly flush the stream.>>>
这里面我们就可以明确的看到print里面第一个就是可变参数,因此它可以直接传入多个值。
命名参数:
又叫做关键字参数
**变量
可变参数和关键字参数,主要的功能就是配合装饰器进行功能扩展的!!!
就比如:
>>> help(print)
Help on built-in function print in module builtins:print(*args, sep=' ', end='\n', file=None, flush=False)Prints the values to a stream, or to sys.stdout by default.sepstring inserted between values, default a space.endstring appended after the last value, default a newline.filea file-like object (stream); defaults to the current sys.stdout.flushwhether to forcibly flush the stream.>>> print("hello","world",end = "")
hello world>>> print("hello","world",end = "",sep = "+")
hello+world>>>
这里我们可以看到print函数有着end以及分割sep关键字参数。
下面我们依旧是那个案例:
def test(x,y,*args,**kwargs):if len(args) > 0:print(args[0])print(kwargs)print(x + y)test(2,5)
test(2,3,4,5,6,7,a = 123,b = 456,name = "xxx",age = 16)
输出结果:
D:\soft\pythonworkplace>test.py
{}
7
4
{'a': 123, 'b': 456, 'name': 'xxx', 'age': 16}
5D:\soft\pythonworkplace>
{'a': 123, 'b': 456, 'name': 'xxx', 'age': 16}
这个我们叫做字典。
我们也试着去拿值:
def test(x,y,*args,**kwargs):if len(args) > 0:print(args[0])if len(kwargs) > 0:print(kwargs["name"])print(x + y)test(2,5)
test(2,3,4,5,6,7,a = 123,b = 456,name = "xxx",age = 16)
输出结果:
D:\soft\pythonworkplace>test.py
7
4
xxx
5D:\soft\pythonworkplace>
8、函数传递
函数作为参数传递函数内部:
python中函数是对象,python中函数的参数只要是对象即可,所以pyhton中函数可以作为参数传递到函数内部。
注意如下两种情况的不同之处:
def a()pass
def b()pass
b(a) # 函数作为参数传递到函数中
b(a())# 将a的返回值作为参数传递到函数中
案例:
def demo(fn):# 下面这行代码就是一个函数调用# fn是一个函数fn("hello,函数你好")demo(print)
输出结果:
D:\soft\pythonworkplace>test.py
hello,函数你好D:\soft\pythonworkplace>
那么我们可不可以加括号?
def demo(fn):# 下面这行代码就是一个函数调用# fn是一个函数fn("hello,函数你好")demo(print())
输出结果:
Traceback (most recent call last):File "D:\soft\pythonworkplace\test.py", line 657, in <module>demo(print())File "D:\soft\pythonworkplace\test.py", line 655, in demofn("hello,函数你好")
TypeError: 'NoneType' object is not callableD:\soft\pythonworkplace>
这又是什么意思呢?
这里我们也就是等同于如下代码,首先执行调用。
def demo(fn):# 下面这行代码就是一个函数调用# fn是一个函数fn("hello,函数你好")print(print())
demo()
输出结果:
D:\soft\pythonworkplace>test.pyNone
Traceback (most recent call last):File "D:\soft\pythonworkplace\test.py", line 658, in <module>demo()
TypeError: demo() missing 1 required positional argument: 'fn'D:\soft\pythonworkplace>
我们可以看到首先print(print())执行结果为none,然后我们在进行了调用,此时进行报错,也就是none不能被调用。
这里我们也可以进行联想到,print实际存储在堆里面,而栈里面存储的则是print的引用地址。所以我们也就是将print的引用地址传给了fn,从而输出了一段i字符串。
当然,这里直接使用print输出函数可以,同时我们也可以自己构建一个函数进行函数传递:
def demo(fn):# 下面这行代码就是一个函数调用# fn是一个函数fn("hello,函数你好")def print_msg(msg):print(msg)demo(print_msg)
输出结果:
D:\soft\pythonworkplace>test.py
hello,函数你好D:\soft\pythonworkplace>
这里可以看到输出结果是一样的。
所以,python中函数是可以以参数的形式存入函数内部的。带了括号相当于传了函数的返回值。函数带括号表示函数调用,不带括号表示函数引用,代表函数本身。
9、匿名函数以及lambda表达式
匿名函数:没有名称的函数,不能直接调用
python
在lambda
引入之前是没有匿名函数的!
lambda
表达式之后,才通过lambda
实现了匿名函数
lambda(x,b,c):函数体
同样是以上案例:
def demo(fn):# 下面这行代码就是一个函数调用# fn是一个函数fn("hello,函数你好")demo(lambda msg:print(msg))
输出结果:
D:\soft\pythonworkplace>test.py
hello,函数你好D:\soft\pythonworkplace>
这里lambda使用后面加参数这里也就是函数名,冒号后面加返回值,这里则为函数内容。
使用lambda主要用于匿名场景中,进行简化。
lambda本质是简化编写程序的难度!!!!!
10、偏函数
可能存在某个函数,该函数中存在默认值
如果后面调用时,多次需要修改为一个相同的默认值【变成另外一个值】可以使用偏函数实现
我们可以看下int:
>>> help(int)
Help on class int in module builtins:class int(object)| int([x]) -> integer| int(x, base=10) -> integer|| Convert a number or string to an integer, or return 0 if no arguments| are given. If x is a number, return x.__int__(). For floating point| numbers, this truncates towards zero.|| If x is not a number or if base is given, then x must be a string,| bytes, or bytearray instance representing an integer literal in the| given base. The literal can be preceded by '+' or '-' and be surrounded| by whitespace. The base defaults to 10. Valid bases are 0 and 2-36.| Base 0 means to interpret the base from the string as an integer literal.| >>> int('0b100', base=0)| 4|| Built-in subclasses:| bool|| Methods defined here:|| __abs__(self, /)| abs(self)|| __add__(self, value, /)| Return self+value.|
-- More --
我们可以看到base=10,这里int就是整型10进制不用改默认值。如果我们需要进行进制转换:
>>> int("123456")
123456
>>> int("123456",base = 10)
123456
>>> int("123456",base = 8)
42798
>>> int("11111",base = 2)
31
>>>
我们可以重新构建一个函数,只是这里不是10进制,而是二进制,引入functools模块。
1、import functoolsfunctools.partial()2、from functools import partial# 返回一个新的函数 = partial(原函数, 默认值=新值)
使用:
>>> import functools
>>> dir(functools)
['GenericAlias', 'RLock', 'WRAPPER_ASSIGNMENTS', 'WRAPPER_UPDATES', '_CacheInfo', '_HashedSeq', '_NOT_FOUND', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_c3_merge', '_c3_mro', '_compose_mro', '_convert', '_find_impl', '_ge_from_gt', '_ge_from_le', '_ge_from_lt', '_gt_from_ge', '_gt_from_le', '_gt_from_lt', '_initial_missing', '_le_from_ge', '_le_from_gt', '_le_from_lt', '_lru_cache_wrapper', '_lt_from_ge', '_lt_from_gt', '_lt_from_le', '_make_key', '_unwrap_partial', 'cache', 'cached_property', 'cmp_to_key', 'get_cache_token', 'lru_cache', 'namedtuple', 'partial', 'partialmethod', 'recursive_repr', 'reduce', 'singledispatch', 'singledispatchmethod', 'total_ordering', 'update_wrapper', 'wraps']
>>> functools.partial
<class 'functools.partial'>
>>> from functools import partial
>>> partial(int,base=2)
functools.partial(<class 'int'>, base=2)
>>> a = partial(int,base=2)
>>> a
functools.partial(<class 'int'>, base=2)
>>> a("100")
4
>>> a("100",base=10)
100
>>> int("100")
100
>>>
三、递归
递归(recursion
):函数自身调用自身,需要设置递归的终止条件
一定要有终止条件,否则是个死循环。
案例:求 0-n的和
# 求0-n的和
def get_count(n:int):if n == 1:return 1return n + get_count(n - 1)count = get_count(100)
print(f"0-100的和是{count}")
输出结果:
D:\soft\pythonworkplace>test.py
0-100的和是5050D:\soft\pythonworkplace>
递归的内存分析以及优缺点
这里也就牵扯了压栈,弹栈。
这就是栈内进行大量调用执行从而占用大量空间。
这里我们可以尝试着让其调用1000多次:
# 求0-n的和
def get_count(n:int):if n == 1:return 1return n + get_count(n - 1)count = get_count(1000)
print(f"0-100的和是{count}")
输出结果:
D:\soft\pythonworkplace>test.py
Traceback (most recent call last):File "D:\soft\pythonworkplace\test.py", line 668, in <module>count = get_count(1000)^^^^^^^^^^^^^^^File "D:\soft\pythonworkplace\test.py", line 665, in get_countreturn n + get_count(n - 1)^^^^^^^^^^^^^^^^File "D:\soft\pythonworkplace\test.py", line 665, in get_countreturn n + get_count(n - 1)^^^^^^^^^^^^^^^^File "D:\soft\pythonworkplace\test.py", line 665, in get_countreturn n + get_count(n - 1)^^^^^^^^^^^^^^^^[Previous line repeated 996 more times]
RecursionError: maximum recursion depth exceededD:\soft\pythonworkplace>
这里报错,递归错误,已经超过了递归最大数量。
同时,我们可以调用sys内置模块来看递归最大次数:
import sysprint(sys.getrecursionlimit())
# 求0-n的和
def get_count(n:int):if n == 1:return 1return n + get_count(n - 1)count = get_count(1000)
print(f"0-100的和是{count}")
输出结果:
D:\soft\pythonworkplace>test.py
1000
Traceback (most recent call last):File "D:\soft\pythonworkplace\test.py", line 671, in <module>count = get_count(1000)^^^^^^^^^^^^^^^File "D:\soft\pythonworkplace\test.py", line 668, in get_countreturn n + get_count(n - 1)^^^^^^^^^^^^^^^^File "D:\soft\pythonworkplace\test.py", line 668, in get_countreturn n + get_count(n - 1)^^^^^^^^^^^^^^^^File "D:\soft\pythonworkplace\test.py", line 668, in get_countreturn n + get_count(n - 1)^^^^^^^^^^^^^^^^[Previous line repeated 996 more times]
RecursionError: maximum recursion depth exceededD:\soft\pythonworkplace>
当然,我们如果真的要求1到1000以上的和或者其他,我们也可以进行自己设置递归的次数,这里设置2000次最大次数,从而输出1到1500的求和:
import sys# print(sys.getrecursionlimit())
sys.setrecursionlimit(2000)
# 求0-n的和
def get_count(n:int):if n == 1:return 1return n + get_count(n - 1)count = get_count(1500)
print(f"0-100的和是{count}")
输出结果:
D:\soft\pythonworkplace>test.py
0-100的和是1125750D:\soft\pythonworkplace>
练习: 1、求斐波那契数列的第n项值
实现一个函数,求斐波那契数列的第n项值
斐波那契数列:从第三项开始,每一项的值是前两项之和
a[n] = a[n - 1] + a[n - 2]
1 1 2 3 5 8 13 21 34 55 89 ……
实现代码:
def fibonacii(n: int) -> int:if n == 1 or n == 2:return 1return fibonacii(n - 1) + fibonacii(n - 2)print(fibonacii(10))
输出结果:
D:\soft\pythonworkplace>test.py
55D:\soft\pythonworkplace>
2、跳楼梯问题:
f(n)=f(n-1)+f(n-2)
实现代码:
def staircase(n):if n == 1 or n == 2:return nreturn staircase(n - 1) + staircase(n -2)print(staircase(10))
输出结果:
D:\soft\pythonworkplace>test.py
89D:\soft\pythonworkplace>
3、不死兔子问题:
小明得到了一对兔子
1 1 1 1 2 3 4 5 7 10 14 19 26 36
a[n] = a[n - 1] + a[n - 4]
实现代码:
def rabbit(n):"""求不死兔子数量"""if n <= 4:return 1else:return rabbit(n - 1) + rabbit(n -2)print(rabbit(8))
输出结果
D:\soft\pythonworkplace>test.py
8D:\soft\pythonworkplace>
四、容器
容器本质就是用来存储大量数据的一种数据结构
容器篇:
list
set
tuple
dict
线性表:
指的是一种有顺序的存储表
- 数组(array):
大小固定、类型固定、内存存储地址是连续的
优点:
查询效率非常高:查询时间复杂度:O(1)
缺点:
更新(删除、增加)比较麻烦,需要内存进行挪动 - 2、链表(
list
):
大小不固定、内存存储地址不一定连续
它的优缺点和数组正好相反 - 3、栈(
stack
):
FILO LIFO
- 4、队列(
queue
)
FIFO LILO
list(列表)
注意: python中的列表底层是使用双向链表实现的!!!
五、作业:
作业1
判断以下哪些不能作为标识符
A、aB、¥aC、_12D、$a@12E、falseF、False
作业2:
输入数,判断这个数是否是质数(要求使用函数 + for循环)
实现代码:
um = int(input("请输入一个整数:"))
def work_1(num):flag = Truefor i in range(2,num // 2 + 1):if num % i == 0:flag = Falsebreakif flag:print(f"{num}为质数")else:print(f"{num}为合数")work_1(num)
作业3:
求50~150之间的质数是那些?
实现代码:
def work_9():for num in range(50,101):for i in range(2,num):if num % i == 0:breakelse:print(num)work_9()
作业:
4打印输出标准水仙花数,输出这些水仙花数
实现代码:
def work_10():for a in range(1,10):for b in range(0,10):for c in range(0,10):num = a * 100 + b * 10 + countif num == a ** 3 + b ** 3 + c ** 3:print(num)work_10()
作业5:
验证:任意一个大于9的整数减去它的各位数字之和所得的差,一定能被9整除.
实现代码:
def work_2(num):for i in range(9,num):if (num - num % 10) & 9 == 0:return Truereturn False
for i in range(100):if work_2(i):print(f"{i}可以被整除")
作业6:
一个五位数,若在它的后面写上一个7,得到一个六位数A,
若在它前面写上一个7,得到一个六位数B,B是A的五倍,求此五位数.
实现代码:
def work_4():for i in range(10000,100000):a = i * 10 + 7b = 7 *100000 +iif b == a * 5:return iprint(get(num))
作业7:
求十进制数字的二进制编码:求十进制数字的二进制编码中的1的数量
实现代码:
作业8:
求1~100之间不能被3整除的数之和
实现代码:
def work_5():sum = 0for i in range(1,101):sum += isum1 = 0for j in range(1,101):if j % 3 != 0:sum1 = jsum1 += jsum2 = sum - sum1print(f"1~100之间不能被3整除的数之和:{sum2}")work_5()
作业9:
给定一个正整数N,找出1到N(含)之间所有质数的总和
实现代码:
num = int(input("请输入一个正整数:"))
def work_6(N):sum = 0for i in range(1,N+1):for j in range(2,i // 2 + 1):if i % j == 0:breaksum += iprint(f"所有质数的总和:{sum}")work_6(num)
作业10:
计算PI(公式如下:PI=4(1-1/3+1/5-1/7+1/9-1…)
实现代码:
num = int(input('请输入正整数n:'))
def work_7(n):x = 0a = 0for i in range(1 , n+1 , 2):x += 1 / i * (-1) ** a a += 1print("PI的近似值:",4 * x)work_7(n)
作业11:
求a+aa+aaa+…+aaaaaaaaa=?其中a为1至9之中的一个数,项数也要可以指定
实现代码:
def work_8(n):count = 0num = 0for i in range(n):num += n * 10 ** icount += numreturn count
num = int(input("请输入一个1到9的整数:"))
print(work_8(num))
作业12:
找出10000以内能被5或6整除,但不能被两者同时整除的数(函数)
实现代码:
作业13:
不死兔子和跳楼梯问题
实现代码:
作业14:
汉诺塔问题
实现代码: