1.13 函数/方法
主要解决的问题:将那些具有**独立性功能**的,且**重复的代码**进行封装
- 这一段代码,专门用于处理某一个问题
比如素数问题:
```python
a = 10
b = 110
c = 129087
# 哨兵:监控状态变化
flag = True # 默认是素数
for n in range(2, a // 2 + 1):
if a % n == 0:
flag = False
break
if flag:
print("YES")
else:
print("No")
# 哨兵:监控状态变化
flag = True # 默认是素数
for n in range(2, b // 2 + 1):
if b % n == 0:
flag = False
break
if flag:
print("YES")
else:
print("No")
# 哨兵:监控状态变化
flag = True # 默认是素数
for n in range(2, c // 2 + 1):
if c % n == 0:
flag = False
break
if flag:
print("YES")
else:
print("No")
```
![image-20240419192620231](https://zh-1258460726.cos.ap-nanjing.myqcloud.com/image-20240419192620231.png)
> 到底什么是函数,就是一个具有固定功能的一段代码,根据不同输入的参数,进行同样的计算,得到不同的结果
Python当中 函数的语法格式:
```
def 函数名(参数列表):
函数体,具体的执行内容
return 返回值
# 如果函数不需要返回 则可以不写return
# return 它仅仅表示结束当前函数 如果有返回值则写上 没返回值可以不写return 默认返回None
# 函数必须先定义 再调用(除了面向对象在类中定义函数时)
```
素数的问题进行函数化:
```python
# 素数问题
def isSushu(num):
for n in range(2, num // 2 + 1):
if num % n == 0:
return False
return True
# TypeError: isSushu() missing 1 required positional argument: 'num'
# NameError: name 'isSushu' is not defined
# isSushu()
def isSushuNoReturn(num):
for n in range(2, num // 2 + 1):
if num % n == 0:
print(False)
return
print(True)
return # 其实可以不写 但是存在 (隐藏的)
# print(isSushu(11))
print(isSushuNoReturn(11))
```
**关于函数局部变量的一些问题**
```python
n = 10
def test01(n):
# 局部变量n 用于接受外部变量的数据
n = 20 # n是test01内部创建的一个变量
test01(n)
print(n)
arr = [1,2,3]
def test02(arr):
# 局部变量arr 用于接受外部变量的数据
arr[0] = 666 #arr是test02内部创建的一个变量
test02(arr)
print(arr)
```
![image-20240419195320028](https://zh-1258460726.cos.ap-nanjing.myqcloud.com/image-20240419195320028.png)
```python
n = 100
def test03():
n = 200 # 函数内部创建的变量
m = 300 # 函数内部创建的变量
test03()
print(n)
print(m) # NameError: name 'm' is not defined
```
在函数的外面,并不能调用函数内部创建的变量(局部变量)
> 一定要区分,在函数内部
>
> - 操作的变量是局部的还是全局的
> - = 是创建还是修改
>
> ```python
> n = 100
> def test04(n): # n 是以局部变量的形式创建的 然后在接收全局n的100
> n = 200 # 修改
> m = 300 # 创建
> test04(n)
> print(n)
> print(m)
> ```
如何修改外部变量,用`global`关键字去指定
```python
n = 100
m = 300
def test05():
n = 666
print(n)
global n, m # 事先指定哪些变量是全局的
n = 200
m = 400
print(n)
# SyntaxError: name 'n' is used prior to global declaration
# 在函数内部 局部变量和全局变量 不要重名
test05()
print(n)
print(m)
```
```python
n = 100
m = 300
def test06():
global n
n = 200 # 已经被声明为全局
m = 400 # 局部变量
test06()
print(n, m)
```
```python
def test07(arr): # 局部变量 函数被调用时 指向[1,2,3]
arr = [2, 3, 4] # 被修改 指向[2,3,4]
arr = [1, 2, 3]
test07(arr)
print(arr)
```
**Python主函数的问题**
函数还能将代码进行模块化,解耦,方便阅读、维护、设计
```python
# 程序的入口 看成主函数
if __name__ == "__main__":
print("Hello World")
```
**关于函数的具体执行的流程**
> - 函数的运行 是基于栈内存的
> - 每一个函数看作是栈内存的元素
> - 哪个函数在栈顶 那么它就优先执行 直到调用别的函数 当前函数暂停执行
> - 函数但凡被调用 则加载到栈内存中 成为新的栈顶
> - 函数执行完毕(遇到return) 则弹栈 新的栈顶继续执行
>
> 具体看录屏的动画
```python
# 递归
def show():
arr = [0] * 1000000000000000 # MemoryError 堆内存溢出
print("show") # RecursionError: maximum recursion depth exceeded 栈内存溢出
show()
def main():
show()
if __name__ == "__main__":
main()
```
> 所谓的递归 其实就是函数自身调用自身
>
> 栈内存溢出 栈主要存函数的 函数存不下了 (主要还是因为递归)
>
> 堆内存溢出 堆主要存对象的 对象存不下了(一直在创建新的数据对象)
**递归的应用**
递归如果设计不当,容易导致占内存溢出
所以之后在写递归的时候,需要注意啥?**注意递归什么时候结束**!
> 递归,它可以将一个大型复杂的问题,进行逐层的化解,化为若干个较小的问题,同时这些较小的问题也可继续进行化解为若干个更小的问题,直到该问题不能被化解为止(终止递归)->原子问题是可以直接被求解的
>
> 所以,将所有原子问题的解,进行合并,就得到了原问题的解
>
> - 原子问题之间的求解,不能相互作用,互不影响!
> - 每一层问题的求解方式,都是一致的!
>
> 上述的内容,就是【**分治算法**】
但凡是迭代的问题,都可以被递归写,但反过来就不一定了
同样的一个问题,用迭代写的代码较多,用递归写的代码较少
递归可以用少量的代码来解决较大的问题
> 人用迭代,神用递归
```python
# (1)计算1~100之间的求和问题
"""
f(100) = 1+2+3+4+....+99+100
f(99) = 1+2+3+4+...+98+99
f(n) = f(n - 1) + n
f(100) = f(99) + 100
f(99) = f(98) + 99 1+2+3+...+98 + 99
....
f(4) = f(3) + 4 1+2+3 + 4
f(3) = f(2) + 3 1+2 + 3
f(2) = f(1) + 2 1 + 2
f(1) = 1 # 递归的边界条件
f(100)->f(1) 递归的前进段
f(1) = 1 递归的边界条件
f(1)->f(100) 递归的返回段
1, n = 1
f(n)
f(n-1) + n, n > 1
"""
def nSum(n):
if n == 1:
return 1
return nSum(n - 1) + n
#(2)斐波那契数列
"""
1 1 2 3 5 8 13 21 34 55 89 ...
f(n) = f(n-1) + f(n-2)
f(5)
f(4) + f(3)
f(3) + f(2) f(2) + f(1)
f(2) + f(1)
1, n ∈[1,2]
f(n)
f(n-1) + f(n-1), n > 2
"""
def fibo(n):
if n == 1 or n == 2:
return 1
return fibo(n - 1) + fibo(n - 2)
#(3)二分查找
def binarySearch(arr, L, R, key):
if L > R:
return -1
M = (L + R) // 2
if arr[M] == key:
return M
elif arr[M] < key:
return binarySearch(arr,M + 1, R, key)
else:
return binarySearch(arr,L, M - 1, key)
def main():
print(nSum(100))
#print(fibo(40))
arr = [1,2,3,4,5,6,7,8,9,10]
key = 11
print(binarySearch(arr, 0, len(arr) - 1, key))
if __name__ == "__main__":
main()
```
```python
#(4) 快速排序(三路快速排序)
import random
def quickSort(arr, L, R):
if L > R:
return
lt = L
gt = R + 1
idx = random.randint(0 , R - L) + L
arr[L], arr[idx] = arr[idx], arr[L]
V = arr[L]
i = L + 1
while i < gt:
if arr[i] < V:
arr[lt + 1], arr[i] = arr[i], arr[lt + 1]
lt += 1
i += 1
elif arr[i] > V:
gt -= 1
arr[gt], arr[i] = arr[i], arr[gt]
else:
i += 1
arr[L], arr[lt] = arr[lt], arr[L]
# 递归处理左边
quickSort(arr, L, lt - 1)
# 递归处理右边
quickSort(arr, gt, R)
def main():
global count
arr = [0] * 50
for i in range(len(arr)):
arr[i] = random.randint(0,1000)
quickSort(arr, 0, len(arr) - 1)
print(arr)
if __name__ == "__main__":
main()
```
```python
"""
(5) 汉诺塔问题
前3个 X -> Z
前2个 X -> Y
前1个 X -> Z
第2个 X -> Y
前1个 Z -> Y
第3个 X -> Z
前2个 Y -> Z
前1个 Y -> X
第2个 Y -> Z
前1个 X -> Z
"""
def hanoi(n, begin, mid, end):
if n == 1:
print(begin + " -> " + end)
else:
hanoi(n - 1, begin, end, mid)
print(begin + " -> " + end)
hanoi(n - 1, mid, begin, end)
def main():
X = "X"
Y = "Y"
Z = "Z"
hanoi(3, X, Y, Z)
if __name__ == "__main__":
main()
```
```python
"""
(6) 全排列
"ABC"
ABC
ACB
BAC
BCA
CAB
CBA
"""
result = [] # set集合适用于去重复的操作
def permutation(arr, left, right):
if left == right:
s = ""
for c in arr:
s += c
if s not in result:
result.append(s)
else:
for i in range(left, right + 1):
arr[i], arr[left] = arr[left], arr[i]
permutation(arr, left + 1, right)
arr[i], arr[left] = arr[left], arr[i]
def main():
s = input()
arr = list(s)
permutation(arr, 0, len(arr) - 1)
print(result)
if __name__ == "__main__":
main()
```
## 函数编程练习
**Demo55**
```python
def rule01(password):
return len(password) >= 8
def isAlpha(c):
return 'a' <= c <= 'z' or 'A' <= c <= 'Z'
def isDigit(c):
return '0' <= c <= '9'
def rule02(password):
for c in password:
if not (isAlpha(c) or isDigit(c)):
return False
return True
def rule03(password):
count = 0
for c in password:
if isDigit(c):
count += 1
return count >= 2
def rule04(password):
count = 0
for c in password:
if 'A' <= c <= 'Z':
count += 1
return count >= 2
if __name__ == "__main__":
password = input()
if rule01(password) and rule02(password) and rule03(password) and rule04(password):
print("YES")
else:
print("No")
```
**Demo56**
```python
# 判断素数
def isSuShu(num):
for n in range(2, num // 2 + 1):
if num % n == 0:
return False
return True
# 判断回文
def isHuiWen(num):
return num == reverse(num)
# 整数翻转
"""
123 % 10 = 3
12 % 10 = 2
1 % 10 = 1
0*10 + 3 = 3
3*10 + 2 = 32
32*10 + 1 = 321
"""
def reverse(num):
revNum = 0
while num != 0:
revNum = revNum * 10 + num % 10
num //= 10
return revNum
if __name__ == "__main__":
num = 2
count = 0
while count < 100:
if isSuShu(num) and isHuiWen(num):
print(num, end = " ")
count += 1
if count % 10 == 0:
print()
num += 1
```
**Demo68**
```python
import random
def createPath(length):
path = ""
for i in range(length):
if random.randint(0,1) == 1: # [0,1]
path = path + "R"
else:
path += "L"
return path
def countR(path):
count = 0
for c in path:
if c == "R":
count += 1
return count
def main():
arr = input().split(" ") # ["5", "8"]
balls = int(arr[0]) # 球的个数
slots = int(arr[1]) # 槽子的个数
box = [0] * slots # 槽子数组
for i in range(balls):
path = createPath(slots - 1)
print(path)
index = countR(path)
box[index] += 1
print(box)
if __name__ == "__main__":
main()
```
**Demo72**
```python
import random
def createPasswd(word, state):
passwd = ""
for i in range(len(word)):
if state[i]:
passwd += "#"
else:
passwd += word[i]
return passwd
def isGameOver(state):
return True not in state
def isChangeState(state, word, ch):
for i in range(len(word)):
if word[i] == ch:
if state[i]:
state[i] = False
else:
return False
return True
def main():
# 单词组
words = ["banana", "orange", "computer", "refrigerator", "program"]
while True:
# 明文单词
word = words[random.randint(0, len(words) - 1)]
# 单词的状态
state = [True] * len(word)
# 制作密文
passwd = createPasswd(word, state)
# 错误次数
missed = 0
while not isGameOver(state):
ch = input("Enter a letter in word " + passwd + " >")
if ch in word:
if isChangeState(state, word, ch):
passwd = createPasswd(word, state)
else:
print(ch + " is already in the word")
else:
missed += 1
print(ch + " is not in the word")
print(f"The word is {word}. You missed {missed} time")
choice = input("是否继续? y/n >")
if choice == "n":
break
if __name__ == "__main__":
main()
```