Python基础——认识函数(二)
- 1.函数的返回值
- 2.文档字符串
- 3.函数的作用域
- 4.命名空间
- 5.递归函数
- 小试牛刀
1.函数的返回值
- 返回值是函数执行后的结果
- 通过return来指定函数的返回值
- return后面可以跟任何对象,甚至是一个函数
- return会直接跳出函数,不会执行后续的语句
注意:如果仅仅写一个return或不写,返回是None
# 函数的返回值
# 函数一
def my_fun1(a,b):
c = a + b
# 返回值通过return传递
return c
# 函数二
def my_fun2(a,b):
# 返回值是函数
return my_fun1(a,b)
# 函数三
def my_fun3():
# 返回值空
return
# 函数四
def my_fun4(a,b):
c= a + b
return c
d = a - b
print(d)
result = my_fun1(1,2)
print(result) #3
result2 = my_fun2(3,2)
print(result2) #5
result3 = my_fun3()
print(result3) #None
result4 = my_fun4(7,5)
print(result4) #12
2.文档字符串
- 文档字符串是用于解释文档程序的重要工具,它没有被执行,但它能帮助解释程序文档
- 在定义函数时,可以在函数内部编写文档字符串,文档字符串就是对函数的说明
- help()是Python中内置函数,通过help()函数可以查询Python中函数的用法
# 文档字符串
def my_sum(a,b):
# 下面'''xxx'''内的内容就是文档字符串,起解释函数参数的作用
''' :param a:the first number used to add :param b:the second number used to add :return c:the result of (a + b) '''
c = a + b
return c
# 调用help()查看函数
help(my_sum)
# Help on function my_sum in module __main__:
#
# my_sum(a, b)
# :param a:the first number used to add
# :param b:the second number used to add
# :return c:the result of (a + b)
3.函数的作用域
- 作用域(scope):作用域指的是变量生效的区域
- 在Python中一共有两种作用域
- 全局作用域
- 全局作用域在程序执行时创建,在程序执行结束时销毁
- 所有函数以外的区域都是全局作用域
- 在全局作用域中定义的变量,都是全局变量,全局变量可以在程序的任意位置进行访问
- 函数作用域
- 函数作用域在函数调用时创建,在调用结束时销毁
- 函数每调用一次就会产生一个新的函数作用域
- 在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问
- 全局作用域
- 可以使用global在函数内部声明,使其能在函数内部对函数外的变量进行操作
# 作用域
# 在函数外,为全局变量
num1 = 10
num2 = 20
def my_sum(a,b):
c = a + b
# 在函数内,为局部变量
num1 = 5
# 使用global将num2声明为全局变量
global num2
num2 = 66
print('函数内部:num1 =',num1)
print('函数内部:num2 =', num2)
return c
result = my_sum(7,8)
# 函数内部:num1 = 5
# 函数内部:num2 = 66
print('函数外部:num1 =',num1) #函数外部:num1 = 10
print('函数外部:num2 =',num2) #函数外部:num2 = 66
4.命名空间
- 命名空间实际上就是一个字典,是一个专门用来存储变量的字典
- locals()用来获取当前作用域的命名空间
- 如果在全局作用域中调用locals()则获取全局命名空间,如果在函数作用域中调用locals()则获取函数命名空间
- 返回值是一个字典
# 命名空间
num = 6
def fun(a,b):
c = a * b
return c
result = fun(12,4)
print(result) #48
#获取当前命名空间
namespace = locals()
print(type(namespace)) #<class 'dict'>
print(namespace)
# 输出结果:
# {'__name__': '__main__', '__doc__': None, '__package__': None,
# '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000027B6E416080>,
# '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>,
# '__file__': 'E:/day10/函数.py', '__cached__': None, 'num': 6,
# 'fun': <function fun at 0x0000027B70079620>, 'result': 48, 'namespace': {...}}
# 可以查看我们在当前页面定义的num、fun以及result是否在其中
print(namespace['num']) #6
print(namespace['fun']) #<function fun at 0x000001856B5196A8>
print(namespace['result']) #48
# 试试查看当前空间不包含的参数 s
print(namespace['s']) #KeyError: 's'
# 使用命名空间调用函数
print(namespace['fun'](12,4)) #48
5.递归函数
- 递归是解决问题的一种方式,它的整体思想,是将一个大问题分解为一个个的小问题,直到问题无法分解时,在去解决问题
- 递归式函数有2个条件:
- 1.基线条件:问题可以被分解为最小问题,当满足基线条件时,递归就不执行了
- 2.递归条件:可以将问题继续分解的条件
# 递归函数
def my_fun(my_str):
''' :function:评定输入是否为回文字符串 :my_str: 输入字符串 type:str :return : True(是回文字符串) False(不是回文字符串) '''
# 基线条件
if len(my_str) <2:
return True
elif my_str[0] != my_str[len(my_str)-1]:
return False
else:
# 递归条件:字符串首尾相同,去掉字符串首尾
return my_fun(my_str[1:-1])
print(my_fun('123321')) #True
print(my_fun('pytyp')) #True
print(my_fun('ajfoij')) #False
小试牛刀
- 汉诺塔游戏:
现在有ABC三根柱子。要求:将A柱所有的圆盘放到C柱。在移动的过程中可以借助B柱。并且规定大圆盘不能放小圆盘上面,每次只能移动一个盘子。用递归的方式来解决汉诺塔问题。
对于初学者来说真心有难度,下面可能只是现在能想到的一种较难的实现方法,若有更好的方法,欢迎提出,谢谢!
# 汉诺塔游戏:
# 现在有ABC三根柱子。要求:将A柱所有的圆盘放到C柱。
# 在移动的过程中可以借助B柱。并且规定大圆盘不能放小圆盘上面,
# 每次只能移动一个盘子。用递归的方式来解决汉诺塔问题
# 分析
''' # 初始化 在游戏开始时,假设放置了n个圆盘在A柱子上,由于大圆盘不能在小圆盘上, 所以A上的圆盘从上往下以此变小,我们将这n个从上到下的圆盘编号为: 1,2,3,4...n-1,n # 分析 当有1个盘子:A->C mov(A,C,1) <=> mov(A,C,1) 当有2个盘子:A->B,A->C,B->C mov(A,C,2) <=> mov(A,B,1) + mov(A,C,1) + mov(B,C,1) 当有3个盘子:A->C,A->B,C->B, A->C, B->A,B->C,A->C mov(A,C,3) <=> mov(A,B,2) + mov(A,C,1) + mov(B,C,2) ... 当有n个盘子: mov(A,C,n) <=> mov(A,B,n-1) + mov(A,C,1) + mov(B,C,n-1) 其中 :mov(src,dst,n)表示将n个圆盘从src移到dst(不是直接一下移动了n个,是一步步通过空余柱子转移从而移动n个的) # 基线条件 只剩最后一个圆盘需要移动 # 递归条件 mov(A,C,n) <=> mov(A,B,n-1) + mov(A,C,1) + mov(B,C,n-1) 其中为了表示哪个柱子做了桥梁用于给传递圆盘用作过渡,便还需要添加一个参数med作为这个"桥梁" 即上面的式子可一般化为: mov(src,dst,med,n) = mov(src,med,dst,n-1) + mov(src,dst,med,1) + mov(med,dst,src,n-1) '''
# 获取A,B,C三个柱子上的圆盘数量
def put_A_num(n):
# A柱子
src = ['A',':']
for i in range(n,0,-1):
src.append(i)
return src
def put_B_num(n):
# B柱子
src = ['B',':']
for i in range(n,0,-1):
src.append(i)
return src
def put_C_num(n):
# C柱子
src = ['C',':']
for i in range(n,0,-1):
src.append(i)
return src
# 用于显示每一步移动操作后柱子上圆盘的情况
def show_data(data1,data2,data3,character):
# 显示对应character的柱子上的圆盘
if data1[0] == character:
print(data1[0:1],data1[2:])
elif data2[0] == character:
print(data2[0:1], data2[2:])
else:
print(data3[0:1], data3[2:])
# 用于实现从A柱子上将n个圆盘移到C柱子上
def mov(src, dst, med, n):
global step
if n == 1:
# 当只需移动一个盘子时
step += 1
disk = src.pop()
dst.append(disk)
# 下面全是用于显示的操作,与移动盘子无关
print('第'+str(step)+'步:')
print('将'+str(disk)+'从'+src[0]+'中移到'+dst[0])
show_data(src, dst, med, 'A')
show_data(src, dst, med, 'B')
show_data(src, dst, med, 'C')
print()
else:
# 将移动n个盘子分为三步执行
mov(src, med, dst, n-1)
mov(src, dst, med, 1)
mov(med, dst, src, n-1)
print('共用了'+str(step)+'步!')
# 将所有函数整合在一个函数中
def HNT_game_start(n):
global step
step = 0
src = put_A_num(n)
med = put_B_num(0)
dst = put_C_num(0)
print('下面是你输入的参数生成的对应柱子上的圆盘!')
print(src[0:1], src[2:])
print(med[0:1], med[2:])
print(dst[0:1], dst[2:])
print()
mov(src, dst, med, n)
# 通过你输入的参数查看如何移动
num = int(input('欢迎使用汉诺塔游戏破解版,请输入你想从A柱子移动到A柱子的数量:'))
HNT_game_start(num)
当A上悬挂的盘子数量为3时(太长了不好截图,),执行结果如下: