递归函数
在函数内部,可以调用其他函数。如果一个函数在内部调用自己本身,那这个函数就是递归函数。
举个例子,我们来计算阶乘n! = 1 * 2 * 3 * ... * n
,用函数fact(n)
表示,可以看出:
fact(n) = n! = 1 * 2 * 3 * ... * (n-1) * n = fact(n-1) * n
所以,fact(n)
可以表示为fact(n-1)*n
,只有当n=1的时候需要特殊处理
于是,fact(n)
用递归的方式写出来就是:
def fact(n):
if n == 1:
return 1
return n * fact(n-1)
如果我们计算fact(5),可以看到
--> fact(5)
--> 5 * fact(4)
--> 5 * (4 * fact(3))
--> 5 * (4 * (3 * fact(2)))
--> 5 * (4 * (3 * (2 * fact(1))))
--> 5 * (4 * (3 * (2 * 1)))
--> 5 * (4 * (3 * 2))
--> 5 * (4 * 6)
--> 5 * 24
--> 120
如果递归函数不断地调用函数自身,那么这个递归函数就会进入一个死循环,因此我们应该给递归函数一个明确的结束条件。
递归的核心:递进的时候能够达到一个结果,问题规模越来越小(不一定要真正的达到);设置一个条件后,能够让最后一次函数调用结束。
递归有两个明确的阶段:
- 递推:一层一层的调用下去,进入下一层后,问题规模都会减小。
- 回溯:递归遇到终止条件后,会从最后往回一级一级的把值返回来。
递归函数有3个特点:
- 直接或间接的调用自身
- 具有结束条件,防止递归外溢
- 代码规模逐渐减少
递归函数的优点是定义简单,逻辑清晰,缺点是过深的调用会导致栈溢出。
理论上,所有的递归函数都可以写成循环的方式,但是循环的逻辑不如递归清晰。
递归就是函数调用函数本身,然后有结束条件。
内置方法
-
bytes()
解码字符
res = bytes('你好', encoding='utf8')
print(res)
# b'xe4xbdxa0xe5xa5xbd'
-
chr()/ord()
chr()参考ASCII码表将数字转成对应字符;ord()将字符转换成对应的数字。
print(chr(97))
# a
print(ord('a'))
# 97
-
divmod()
分栏
print(divmod(10, 3))
# (3, 1)
-
enumerate()
带有索引的迭代
lt = ['a', 'b', 'c']
for i in enumerate(lt):
print(i)
# (0, 'a')
# (1, 'b')
# (2, 'c')
-
eval()
把字符串翻译成数据类型
lis = '[1, 2, 3]'
lis_eval = eval(lis)
print(lis_eval)
# [1, 2, 3]
-
hash()
是否可哈希
print(hash(1))
# 1
面向过程编程
面向过程编程绝对不是函数编程那么简单,面向过程是一种编程思想,而编程思想是不依赖具体的语法的。即我们不依赖于函数,也可以基于面向过程的思想编写程序。
面向过程编程,过程是解决问题的步骤,即先干什么后干什么
基于面向过程设计的程序,就好比在设计一条流水线,是一种机械式的思维方式
优点:复杂的问题流程化,进而简单化
缺点:功能与功能之间不独立,可扩展性差,牵一发而动全身