python基础九 函数(中)作用域、命名空间、递归函数

1. 文档字符串

  • 查看帮助文档__doc__和help()函数
  • __doc__查看帮助文档
#吃榴莲的过程
def func():
    """
    功能:这是一个吃榴莲的过程
    参数:
    返回值:
    """
    print("拿出榴莲")
    print("榴莲皮去掉")
    print("果肉放进嘴里")
    return "太香了"
func()
#用__doc__查看func这个函数的帮助文档
print(func.__doc__)
  • help()是Python中内置函数,通过help()函数可以查询Python中函数的用法
# help()函数用法:help(函数名)
help(input) #直接运行,就会调用出input这个函数的用法
  • 在定义函数时,可以在函数内部编写文档字符串,文档字符串就是对函数的说明
def fun(a, b, c):
    """
    这是一个文档字符串的示例
    这个函数是做什么用的。。。。

    :param a: 作用  类型  默认值
    :param b: 作用  类型  默认值
    :param c: 作用  类型  默认值
    :return:  需不需要返回值
    """
    return 123
help(fun)#查看fun这个函数的用法

2. 函数的作用域

2.1 全局作用域

  • 概念
    全局作用域在程序执行时创建,在程序执行结束时销毁;所有函数以外的区域都是全局作用域;在全局作用域中定义的变量,都是全局变量,全局变量可以在程序的任意位置进行访问
  • 在函数外部定义的变量
a = 123
def fun():
	b = 456
	print('函数内部a = ',a)
	print('函数内部b =',b)
fun()
print('函数外部a = ',a) # 输出结果为123,变量a是定义在函数外面,所以可以在任何地方使用,a就是全局变量
print('函数外部b = ',b) # 运行时会报错,因为b是函数内部的变量,不能再函数外面使用。
  • 在函数内部的变量,但是变量前面+global,此时函数的局部变量就会变成全局变量。
def func():
    global a #用global声明a是全局变量
    a = 123
    b = 456
    print('函数内部a = ',a) # 在函数内部可以正常输出
    print('函数内部b =',b)
func()
print('函数外部a = ',a)  # 在函数外部也可以正常输出,因为global a,在函数内部声明a为全局变量,所以在任何地方都可以访问
print('函数外部b = ',b)  # 但是b是在函数内部的变量,并没有声明b为全局变量,所以在函数外部,是不能访问到b。打印时会报错。
  • global总结

    • 如果函数外部有这个全局变量,在函数内部使用global关键字,可以修改全局变量。
    a = 1000
    def fun1():
        global a # 函数内给全局变量使用global,可以修改全局变量
        a = 2000  # 重新给全局变量赋值
        print("a修改后在函数内部",a)
    fun1()
    print("a修改后在函数外部",a)
    #输出结果:
    a修改后在函数内部 2000
    a修改后在函数外部 2000
    #在函数内部可以直接获取全局变量,但是无法直接修改全局变量,需要通过global修改。
    f = 101 
    def fun2():
    	f = 102
    	print(f)  # 这会报错,在函数内部可以直接获取全局变量,但是无法直接修改全局变量,需要通过global修改,用global f ,才能f=102
    fun2()
    print(f)
    
    • 如果函数外部没有这个全局变量,在函数内部使用global关键字,可以定义全局变量。

2.2 函数内部作用域

  • 概念
    函数作用域在函数调用时创建,在调用结束时销毁;函数每调用一次就会产生一个新的函数作用域;在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问。
a = 123
def fun1():
    b = 456
    print("a全局变量",a)
    print("b局部变量",b)
fun1()
print("a全局变量",a)
print("b局部变量",b)#会报错,因为b是函数局部作用域里设定的变量,称之为局部变量,函数外部是不可以访问的。

3. 函数名的使用(重点)

  • python中的函数可以像变量一样,动态创建、销毁、当参数传递、作为返回值,叫做第一类对象,其他语言 不能比拟功能有限。
  1. 函数名是一个特殊的变量,可以当做变量赋值。
def func1():
	print("我是func1")
	return 111
res = func1()
print(res)
# 动态创建函数
func = func1
func()
# 动态销毁函数
del func
func()
  1. 函数名可以作为容器类型数据的元素
def func2():
    print("我是func2")
def func3():
    print("我是func3")
def func4():
    print("我是func4")
    return "func4"
lst = [func2,func3,func4] #将函数名当做列表的的元素
for i in lst:#遍历列表
    i()   #调用函数
  1. 函数名可以作为函数的参数
#函数名作为函数的参数
def myfunc(f):  # f形参
    res = f()   # 形参f是一个函数,既然是一个函数,那么就可以调用,f()
    print(res)
# 此刻f <==> func4 <==> res = func4() print(res)
myfunc(func4)
  1. 函数名可以作为函数的返回值
def myfunc2(f):
    return f
f2 = myfunc2(func4) # f2 = func4
print(f2)  # 打印显示f2 就是func4
f2() # 既然f2 = func4,那么看看可以不可以调用。

4. 命名空间

  • 概念:命名空间实际上就是一个字典,是一个专门用来存储变量的字典。
  • 生命周期:python内置关键字变量>全局变量>局部变量。
    从内存角度分析:python内置变量编译器打开的时候就已经在电脑内存里开辟空间,直到编译器关闭,这一块内存才会释放,所以它的生命周期最长;其次是全局变量,当打开一个文件的时候,全局变量在内存中开辟一个空间,直到文件关闭它的内存才会释放;最后函数局部变量(短命鬼),创建函数的时候,内存开辟一个空间存储这个变量,函数调用完后,变量内存就会释放。
  • locals和globals
    • locals 获取当前作用域中的所有内容
    1. locals 如果在函数外,调用locals(),获取的是打印之前的所有变量,返回字典,全局空间作用域。
    a = 1
    b = 2
    res = locals() # 调用locals()函数
    c = 3
    print(res)
    d = 4
    
    打印结果:
    {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000000001DBF7C8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'F:/software/LG_education/play_test/haha2.py', '__cached__': None, 'a': 1, 'b': 2, 'res': {...}, 'c': 3}
    
    1. locals 如果在函数内,调用locals(),获取的是调用之前的所有变量,返回字典,局部空间作用域。
    a = 1
    def func():
    	b = 2
    	res = locals() # 调用locals()函数
    	c = 3
    	print(res)
    	d =4
    func()
    
    
    打印结果:从结果看出,只获取了locals()函数调用之前变量b
    {'b': 2}
    
    • globals获取全局作用域的所有内容
    1. globals 如果在函数外,调用globals(),获取的是打印之前的所有变量,返回字典,全局空间作用域。
    a = 5
    b = 6
    res = globals()
    c = 7
    print(res)
    d = 8
    
    打印结果:
    {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000000000211F7C8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'F:/software/LG_education/play_test/haha2.py', '__cached__': None, 'a': 5, 'b': 6, 'res': {...}, 'c': 7}
    
    1. globals 如果在函数内,调用globals(),获取的是函数调用之前的所有变量,返回字典,全局空间作用域。
    a = 10
    def func1():
        b = 11
        c = 12
        res = globals()
        d = 13
        print(res)
    ff = 50
    func1()
    zz = 100
    
    打印结果:从结果看出globals只获取全局作用域的变量,不会获取函数局部变量
    {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000000000068F7C8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'F:/software/LG_education/play_test/haha2.py', '__cached__': None, 'a': 10, 'func1': <function func1 at 0x0000000001E870D8>, 'ff': 50}
    
  • globals 返回的是系统的字典
  1. 正常方式定义变量
    zhangsan = '112233'
  2. 通过系统的全局字典添加键值对,可以动态创建全局变量
dic = globals()
print(dic)
# 传递字符串,创建一个变量。
k = "sunwukong"
dic[k] = "齐天大圣"
print(sunwukong)
# 打印结果:齐天大圣
  1. 批量创建全局变量,在函数中
    def func():
    dic = globals()
    for i in range(1,6):
        dic[f'p{i}'] = i
    func()
    print(p1)
    print(p2)
    print(p3)
    print(p4)
    print(p5)
    
    打印结果:
    1
    2
    3
    4
    5
    

5. 递归函数

  • 递归是解决问题的一种方式,它的整体思想,是将一个大问题分解为一个个的小问题,直到问题无法分解时,在去解决问题
  • 递归式函数有2个条件:
  1. 基线条件 问题可以被分解为最小问题,当满足基线条件时,递归就不执行了
  2. 递归条件 可以将问题继续分解的条件
    示例1:
# 递归函数的两个条件
# 1. 基线条件  问题可以被分解为最小的问题,当满足基线条件的时候,再去解决问题  (设定的最大递归深度)
# 2. 递归条件  将问题继续分解的条

# 求任意数n的阶乘
def func(n):
    if n <= 1:  # 基线条件
        return 1  
    return n * func(n-1)  # 递归条件
res = func(5)
print(res)

# 递归函数的两个条件
# 1. 基线条件  问题可以被分解为最小的问题,当满足基线条件的时候,再去解决问题  (设定的最大递归深度)
# 2. 递归条件  将问题继续分解的条件
# 10!            n!          fun(n)   是求n的阶乘的函数
# 10! = 10 * 9!  n*(n-1)!    n * fun(n-1)   求n-1的阶乘的函数
# 9! = 9 * 8!
#.....
# 2! = 2*1!
# 1! = 1
  • 递归函数: 自己调用自己的函数是递归函数
    递:去
    归:回
    一去一回叫递归
    def digui(n):
      print(n,"<===1===>")
      if n > 0:
          digui(n-1)
      print(n,"<===2===>")
      digui(5)
      """
      543210012345
      去的过程:
      	当n=5时 print(5,"<===1===>") 5>0 digui(5-1) <=> digui(4) <=> 当前代码在第4行,代码暂停阻塞。
      	当n=4时 print(4,"<===1===>") 4>0 digui(4-1) <=> digui(3) <=> 当前代码在第4行,代码暂停阻塞。
      	当n=3时 print(3,"<===1===>") 3>0 digui(3-1) <=> digui(2) <=> 当前代码在第4行,代码暂停阻塞。
      	当n=2时 print(2,"<===1===>") 2>0 digui(2-1) <=> digui(1) <=> 当前代码在第4行,代码暂停阻塞。
      	当n=1时 print(1,"<===1===>") 1>0 digui(1-1) <=> digui(0) <=> 当前代码在第4行,代码暂停阻塞。
      	当n=0时 print(0,"<===1===>") 0>0 条件不满足,返回False,不执行调用,print(0,"<===2==>")
      回的过程:
      	n = 1 从阻塞位置第4行继续向下执行print(1,"<===2===>")
      	n = 2 从阻塞位置第4行继续向下执行print(2,"<===2===>")
      	n = 3 从阻塞位置第4行继续向下执行print(3,"<===2===>")
      	n = 4 从阻塞位置第4行继续向下执行print(4,"<===2===>")
      	n = 5 从阻塞位置第4行继续向下执行print(5,"<===2===>")
      	到此代码全部执行结束  543210012345
      
      递归函数有回的过程,有两种情况可以触发:
      (1)当最后一层函数全部执行结束的时候,有触底反弹的过程(回马枪),回到上层函数空间的调用处。
      (2)遇到return 返回值,直接返回上层空间调用处
      递归:
      (1)取得过程就是不停的开辟栈帧空间,在回的时候,就是在不停的释放栈帧空间,递归函数就是不停的开辟和释放栈帧空间的一个完成的过程。
      (2)回的时候有两种触发机制,要么是最后一层函数空间全部执行完毕,要么就是遇到return,都会触底反弹(回马枪)
      (3)写递归函数时候,必须给与跳出的条件,如果递归的层数过多,不推荐使用,容易内存溢出或者蓝屏。
      (4)递归调用每一层空间都是独立的个体,独立的副本,资源不共享。
      函数在运行的时候,需要内存开辟空间才可以,这个空间叫做栈帧空间。
    
      """
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值