Python——函数及递归

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 - i
	for 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.py

D:\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.

    sep
      string inserted between values, default a space.
    end
      string appended after the last value, default a newline.
    file
      a file-like object (stream); defaults to the current sys.stdout.
    flush
      whether 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 + y


add(10,20)

这里我们可以看到输出结果:

D:\soft\pythonworkplace>test.py

D:\soft\pythonworkplace>

输出结果并没有,这又是什么原因?
我们首先来测试函数是否进行执行了:
实现代码:

def add(x,y):
	print("函数执行了吗")
	return x + y


add(10,20)

输出结果:

D:\soft\pythonworkplace>test.py
函数执行了吗

D:\soft\pythonworkplace>

这里我们可以看到函数是执行了的。
这里其实已经是返回了一个结果,我们只是没有进行接收这个值,所以:

def add(x,y):
	return x + y


res = add(10,20)
print(res)

输出结果:

D:\soft\pythonworkplace>test.py
30

D:\soft\pythonworkplace>

下面我们来看下函数的分类。

  • 以函数是否存在返回值
    返回值的函数 return关键字 调用后需要接受返回值
    返回值的函数 没有return关键字 返回值为None
  • 以函数是否存在参数
    有参数函数
    无参数函数

4、局部变量和全局变量:

1、局部变量local variable):又叫做本地变量,定义在函数内部的变量
局部变量只能在当前定义的函数内部有效
2、全局变量global variable):直接定义在模块中的变量,叫做全局变量
在python中,函数内部不允许修改全局变量!!!!
3、实际练习:

# 全局变量
name = "张三"
age = 16

def work_1(msg,show):
	# a就是一个局部变量
	a = 20
	# 全局变量可以直接在函数内部访问
	print(name)
	print(age)
	print(a)

	a += 10
	print(a)

work_1("哦","聊天止于哦哦")

这里我们来猜想下输出结果:

D:\soft\pythonworkplace>test.py
张三
16
20
30

D:\soft\pythonworkplace>

好,那么我们此时进行分步访问测试:
首先我们进行全局变量的访问:

name = "张三"
age = 16

def work_1(msg,show):
	a = 20
	print(name)
	print(age)
	print(a)

	a += 10
	print(a)

work_1("哦","聊天止于哦哦")

print(name)
print(age)

输出结果:

D:\soft\pythonworkplace>test.py
张三
16
20
30
张三
16

D:\soft\pythonworkplace>

我们可以看到我们可以在外界正常访问到全局变量;
接下来我们来访问a的值:

name = "张三"
age = 16

def work_1(msg,show):
	a = 20
	print(name)
	print(age)
	print(a)

	a += 10
	print(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 defined

D:\soft\pythonworkplace>

我们可以看到这里只有a是没有正常访问到的,报错了。
变量a没有被定义。
下面我们接着改变案例的要求,这里要输出张三长了一岁的年龄:

name = "张三"
age = 16

def work_1(msg,show):
	a = 20
	print(name)
	print(age)
	print(a)

	a += 10
	print(a)

	age += 1
	print(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_1
    print(age)
          ^^^
UnboundLocalError: cannot access local variable 'age' where it is not associated with a value

D:\soft\pythonworkplace>

我们可以看到这里报错了,又是什么原因呢?
这里它的意思是找不到局部变量age。
这又是什么原因呢?
正常情况,python拒绝在函数中修改全局变量,但是考虑到特殊情况下的需求,python中如果要修改全局变量,需要提前声明!!!!
如果说我们此时加上一个局部变量age:

name = "张三"
age = 16

def work_1(msg,show):
	age = 1
	a = 20
	print(name)
	print(age)
	print(a)

	a += 10
	print(a)

	age += 1
	print(age)

work_1("哦","聊天止于哦哦")

print(name)
print(age)
# print(a)

输出结果:

D:\soft\pythonworkplace>test.py
张三
1
20
30
2
张三
16

D:\soft\pythonworkplace>

我们可以看到内部输出的age最后加了1,而最终输出的age值依然为我们定义的值16。
下面这个便是全局变量确实需要修改的时候,我们则需要在其使用内部加上声明global:
关键字 global 来声明

name = "张三"
age = 16

def work_1(msg,show):
	global age
	a = 20
	print(name)
	print(age)
	print(a)

	a += 10
	print(a)

	age += 1
	print(age)

work_1("哦","聊天止于哦哦")

print(name)
print(age)
# print(a)

输出结果:

D:\soft\pythonworkplace>test.py
张三
16
20
30
17
张三
17

D:\soft\pythonworkplace>

5、函数在内存中调用问题

a = 10
	def test():
		b = 230
		print("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 += 10
	b += 30
	print(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 200

D:\soft\pythonworkplace>

这里也很好理解。
a和b这里只是局部变量,我们只进行了将x以及y的值分别赋予给了a以及b,也就是值传递,函数内部修改不会影响x以及y因为这是一个值传递。
下面我们来看下一串代码:

def change(a,b):
	a += 10
	b += 30
	print(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.

    sep
      string inserted between values, default a space.
    end
      string appended after the last value, default a newline.
    file
      a file-like object (stream); defaults to the current sys.stdout.
    flush
      whether to forcibly flush the stream.

>>>

我们一般给函数进行标注注释一般在函数的上方,而python不一样,这里必须在函数定义下面的第一行,比如:

def get_circle_area():
	"""
		求圆的面积
	"""
	pass


print(help(get_circle_area))


输出结果:

D:\soft\pythonworkplace>test.py
Help on function get_circle_area in module __main__:

get_circle_area()
    求圆的面积

None

D:\soft\pythonworkplace>

这里none代表返回值为空。
而这里我们打印了所有,我们如果想要打印帮助文档:

def get_circle_area():
	"""
		求圆的面积
	"""
	pass


print(get_circle_area.__doc__)

输出结果:

D:\soft\pythonworkplace>test.py

                求圆的面积


D:\soft\pythonworkplace>

好,我们接着看求圆的面积:

def get_circle_area(r,PI):
	"""
		求圆的面积
	"""
	return r * r * PI


r1 = float(input("请输入圆的半径:"))

print(get_circle_area(r1,3.14))

输出结果:

D:\soft\pythonworkplace>test.py
请输入圆的半径:2
12.56

D:\soft\pythonworkplace>test.py
请输入圆的半径:3
28.26

D:\soft\pythonworkplace>

默认值参数:
如果函数中的某个或者某些参数,在调用时大多数情况下,是一个固定值。
为了调用方便,可以设定默认值。
默认值参数一定要写在普通值参数之后,否则会报错。

如果一个值在大多数情况下取一个值,我们可以默认给他一个值,比如这里PI大多数情况下使用3.14,则:

def get_circle_area(r,PI=3.14):
	"""
		求圆的面积
	"""
	return r * r * PI


r1 = float(input("请输入圆的半径:"))

print(get_circle_area(r1))

输出结果:

D:\soft\pythonworkplace>test.py
请输入圆的半径:4
50.24

D:\soft\pythonworkplace>

当然,如果我给了PI另一个值,那么他肯定是使用给定值,如果没有才采用默认值:

def get_circle_area(r,PI=3.14):
	"""
		求圆的面积
	"""
	return r * r * PI


r1 = float(input("请输入圆的半径:"))

print(get_circle_area(r1))
print(get_circle_area(r1,3.1415926))

输出结果:

D:\soft\pythonworkplace>test.py
请输入圆的半径:3
28.26
28.2743334

D:\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
5

D:\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)
5

D:\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
5

D:\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.

    sep
      string inserted between values, default a space.
    end
      string appended after the last value, default a newline.
    file
      a file-like object (stream); defaults to the current sys.stdout.
    flush
      whether 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.

    sep
      string inserted between values, default a space.
    end
      string appended after the last value, default a newline.
    file
      a file-like object (stream); defaults to the current sys.stdout.
    flush
      whether 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}
5

D:\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
5

D:\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 demo
    fn("hello,函数你好")
TypeError: 'NoneType' object is not callable

D:\soft\pythonworkplace>

这又是什么意思呢?

这里我们也就是等同于如下代码,首先执行调用。

def demo(fn):
	# 下面这行代码就是一个函数调用
	# fn是一个函数
	fn("hello,函数你好")

print(print())
demo()

输出结果:

D:\soft\pythonworkplace>test.py

None
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表达式

匿名函数:没有名称的函数,不能直接调用
pythonlambda引入之前是没有匿名函数的!
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模块。

1import functools
	functools.partial()

2from 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 1

	return n + get_count(n - 1)


count = get_count(100)
print(f"0-100的和是{count}")

输出结果:

D:\soft\pythonworkplace>test.py
0-100的和是5050

D:\soft\pythonworkplace>

递归的内存分析以及优缺点

这里也就牵扯了压栈,弹栈。
这就是栈内进行大量调用执行从而占用大量空间。

这里我们可以尝试着让其调用1000多次:

# 求0-n的和
def get_count(n:int):
	if n == 1:
		return 1

	return 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_count
    return n + get_count(n - 1)
               ^^^^^^^^^^^^^^^^
  File "D:\soft\pythonworkplace\test.py", line 665, in get_count
    return n + get_count(n - 1)
               ^^^^^^^^^^^^^^^^
  File "D:\soft\pythonworkplace\test.py", line 665, in get_count
    return n + get_count(n - 1)
               ^^^^^^^^^^^^^^^^
  [Previous line repeated 996 more times]
RecursionError: maximum recursion depth exceeded

D:\soft\pythonworkplace>

这里报错,递归错误,已经超过了递归最大数量。
同时,我们可以调用sys内置模块来看递归最大次数:

import sys

print(sys.getrecursionlimit())
# 求0-n的和
def get_count(n:int):
	if n == 1:
		return 1

	return 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_count
    return n + get_count(n - 1)
               ^^^^^^^^^^^^^^^^
  File "D:\soft\pythonworkplace\test.py", line 668, in get_count
    return n + get_count(n - 1)
               ^^^^^^^^^^^^^^^^
  File "D:\soft\pythonworkplace\test.py", line 668, in get_count
    return n + get_count(n - 1)
               ^^^^^^^^^^^^^^^^
  [Previous line repeated 996 more times]
RecursionError: maximum recursion depth exceeded

D:\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 1

	return n + get_count(n - 1)


count = get_count(1500)
print(f"0-100的和是{count}")

输出结果:

D:\soft\pythonworkplace>test.py
0-100的和是1125750

D:\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 1
	return fibonacii(n - 1) + fibonacii(n - 2)


print(fibonacii(10))

输出结果:

D:\soft\pythonworkplace>test.py
55

D:\soft\pythonworkplace>

2、跳楼梯问题:
f(n)=f(n-1)+f(n-2)
实现代码:

def staircase(n):
	if n == 1 or n == 2:
		return n
	return staircase(n - 1) + staircase(n -2)


print(staircase(10))

输出结果:

D:\soft\pythonworkplace>test.py
89

D:\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 1
	else:
		return rabbit(n - 1) + rabbit(n -2)


print(rabbit(8))

输出结果

D:\soft\pythonworkplace>test.py
8

D:\soft\pythonworkplace>

四、容器

容器本质就是用来存储大量数据的一种数据结构
容器篇:

list
set
tuple
dict

线性表:
指的是一种有顺序的存储表

  • 数组(array):
    大小固定、类型固定、内存存储地址是连续的
    优点:
    查询效率非常高:查询时间复杂度:O(1)
    缺点:
    更新(删除、增加)比较麻烦,需要内存进行挪动
  • 2、链表(list):
    大小不固定、内存存储地址不一定连续
    它的优缺点和数组正好相反
  • 3、栈(stack):
    FILO LIFO
  • 4、队列(queue)
    FIFO LILO

list(列表)
注意: python中的列表底层是使用双向链表实现的!!!

五、作业:

作业1

判断以下哪些不能作为标识符

	A、a
	B、¥a
	C、_12
	D、$a@12
	E、false
	F、False

作业2:

输入数,判断这个数是否是质数(要求使用函数 + for循环)
实现代码:

um = int(input("请输入一个整数:"))
def work_1(num):
	flag = True
	for i in range(2,num // 2 + 1):
		if num % i == 0:
			flag = False
			break
	if 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:
				break
			else:
				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 + count
				if 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 True
	return 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 + 7
		b = 7 *100000 +i
		if b == a * 5:
			return i

print(get(num))

作业7:

求十进制数字的二进制编码:求十进制数字的二进制编码中的1的数量
实现代码:

作业8:

求1~100之间不能被3整除的数之和
实现代码:

def work_5():
	sum = 0
	for i in range(1,101):
		sum += i
	sum1 = 0
	for j in range(1,101):
		if j % 3 != 0:
			sum1 = j
		sum1 += j
	sum2 = sum - sum1
	print(f"1~100之间不能被3整除的数之和:{sum2}")

work_5()

作业9:

给定一个正整数N,找出1到N(含)之间所有质数的总和
实现代码:

num = int(input("请输入一个正整数:"))
def work_6(N):
	sum = 0
	for i in range(1,N+1):
		for j in range(2,i // 2 + 1):
			if i  %  j == 0:
 				break
		sum += i
	print(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 = 0
	a = 0
	for i in range(1 , n+1 , 2):
		x += 1 / i * (-1) ** a 
		a += 1
	print("PI的近似值:",4 * x)

work_7(n)

作业11:

求a+aa+aaa+…+aaaaaaaaa=?其中a为1至9之中的一个数,项数也要可以指定
实现代码:

def work_8(n):
	count = 0
	num = 0
	for i in range(n):
		num += n * 10 ** i
		count += num
	return count
num = int(input("请输入一个1到9的整数:"))
print(work_8(num))

作业12:

找出10000以内能被5或6整除,但不能被两者同时整除的数(函数)
实现代码:

作业13:

不死兔子和跳楼梯问题
实现代码:

作业14:

汉诺塔问题
实现代码:

你可能感兴趣的:(Python,python,数学建模,开发语言,网络,qt,pycharm)