函数part2

一、函数对象

'''函数是第一类对象,函数是第一等公民'''
1.函数可以被赋值
def foo():  # foo -> 函数的内存地址
    print('hello')
f = foo   # <function foo at 0x000002A3B14F6280>  传递内存地址
print(f)  # hello
f()		 # hello 
2.函数可以当作参数传递给另外一个函数
# x = 1
# def func(a):
#     print(a)
# func(x)
def foo():   # foo->函数的内存地址
    print('hello')
def func(f)
    print(f)  # <function foo at 0x000001DB55436280>  foo -> 函数的内存地址
    f()
func(foo)  # hello
3.函数可以当作函数的返回值
def foo():   # foo->函数的内存地址
    print('hello')
def func(f)
    return f  # 返回foo 的内存地址
res = func(foo)
print(res) # <function foo at 0x00000263781D6280> foo->函数的内存地址
4.函数可以当作容器类型的元素
def foo():   # foo->函数的内存地址
    print('hello')
l = [11, foo, 22]
print(l)  # [11, <function foo at 0x000001E6839B6280>, 22]
l[0]()  # hello

# 例子
def login():
    pass
def register():
    pass
def withdraw():
    pass
def transfer():
    pass
while True:
    print("""
    '0': 'Quit'
    '1': 'Login'
    '2': 'Register'
    '3': 'Withdraw'
    '4': 'Transfer'
    """ )
    choice = input('Input number>>>').strip()
    if choice == '0':
		break
    elif choice == '1'
		login()
    elif choice == '2'
         register()
    elif choice == '3'
         withdraw()
    elif choice == '4'
         transfer()
    else:
         print('Number was error!')
# 存在的问题:代码臃肿
# 解决方案:利用函数对象的特性
def login():
    pass
def register():
    pass
def withdraw():
    pass
def transfer():
    pass
func_dic={
    '1': ['Login', login]
    '2': ['Register', register]
    '3': ['Withdraw', withdraw]
    '4': ['Transfer', transfer]
}
while True:
    print('0  Quit')
    for i in func_dic:
        print('%s  %s' % (i, func_dic[i][0]))
    choice = input('Input number>>>').strip()
    if choice == '0':
        break
    elif choice in func_dic:
        func_dic[choice][1]()
    else:
        print('Number was error!')

二、函数嵌套

1.函数嵌套调用:在调用一个函数的过程中,该函数内部又调用了其他函数-----》能将大功能拆解成几个小功能。
def bar():
    print('hello')
def foo():
    print('world')
    bar()
foo()  # world  \n  hello
# 例子
def max2(x, y):
    if x > y:
        # print(x)
        return x  # max4 需要返回值
    else:
        # print(y)  
        return y  

def max4(a, b, c, d):
    res1 = max2(a, b)
    res2 = max2(res1, c)
    res3 = max2(res2, d)
    # print(res3)
    return res3
# max4(11, 55, 66, 22)  # 66  
max = max4(11, 55, 66, 22)  
print(max)	# 66
2.函数的嵌套定义:在函数内又定义了其他函数-----》封闭,内部的代码外面看不见
def foo():
    def bar():
        print('hello')
        
    # bar()  # hello
    x = 111
foo()  # 无结果,并未调用内部函数bar
f = foo()
print(f)  # None
bar()  # 报错   name 'bar' is not defined  foo() 函数的嵌套定义内部代码外面运行不到
print(x)  # 报错  name 'x' is not defined  foo() 函数的嵌套定义内部代码外面运行不到

# 例子:求圆的周长与面积
from math import pi
def circle(radius):
    def perimiter(radius):
        return 2 * pi * radius
    def area(radius):
        return pi * (radius ** 2)
circle(30)
# 升级需求:函数的嵌套定义内部只调用其中一个
# 知识回顾:f.seek(0, 0),控制指针移动,seek(字节个数, 模式),三种模式:mode = 0, 1, 2
from math import pi
def circle(radius, mode=0):
    def perimiter(radius):
        return 2 * pi * radius
    def area(radius):
        return pi * (radius ** 2)
    if mode == 0:
        return perimiter(radius)
    elif mode == 1:
        return pi * (radius ** 2)
res = circle(30,1)
print(res)  # 2827.4333882308138

三、名称空间与作用域

1.名称空间Namespace:存放名字与内存地址绑定关系的地方
1.1 内置名称空间
    含义:放置python自带的名字,print、len、input
    生命周期:解释器启动则产生,解释器关闭则销毁
1.2 全局名称空间
    含义:放置顶级的名字,如x、y、foo、
    生命周期:运行python文件则立即产生,python文件运行完毕则结束
    x = 10
    
    if 10 > 3:
        y = 996
        
    def foo():
        z = 997
1.3 局部名称空间
    含义:放置函数的名字,如上z
    生命周期:调用函数则产生,函数调用完毕则销毁
    局部变量只能在定义它的函数中使用
# 重要结论
1)名称的查找优先级:局部-》全局-》内置,三者彼此之间无干扰,名称空间无嵌套关系
   永远基于自己当前所在的位置向外查找:LEGB(local --> enclosing --> global --> built-in
   local指一个函数或者方法的内部的名称空间,enclosing指的是闭包内部名称空间,global是全局    名称空间,而built-in是指内置名称空间)
   len = 100
    
   def foo():
       len = 200
       print(len)  # print 站在局部
   foo()  # 200
   print(len)  # 100  站在全局
2)名称空间的嵌套关系是以函数定义为准生成的,与调用位置无关,定义时检测语法,不执行代码      体,确定位置和有没有参数,调用时检测逻辑错误,执行代码体
   
   # 例1
   def foo():
       print(len)  # 在局部,无len则往外的全局找
   
   def bar():
       len = 200
       foo()
   
   len = 100
   
   bar()  # 100  
   # 例2
   x = 111
    
   def foo(): 
       print(x)  # print在局部,局部有x,但存在语法错误,应当先定义后引用
       x = 222
   f1()  # UnboundLocalError:local variable 'x' referenced before assignment  
   # 例3
   x = 1

   def f1():
        x = 2
        def f2():
            x = 3
            print(x)
        f2()
   f1()  # 3

# 关键字
1)global关键字:
   # 例1:不可变类型
   x = 1
   def foo():
       global x   # 声明此处的x升级为全局变量
       x = 2
   foo()
   print(x)
   # 例2:可变类型,影响全局
   x = [11, 22, 33]
   def foo():
       x.append(444)
   foo()
   print(x)  # [11, 22, 33, 44]
2)nonlocal关键字:指E空间,即外层函数,不包含全局,声明一个名字是来自外层函数,如果外层没有也不会找到全局,会报错
   x = 1
   def f1():
       x = 2 
       def f2():
           # global x
           nonlocal x
           x = 3
       f2()
       print(x)  # 3
   f1()
   # print(x)  # 3
2.作用域:发挥作用的范围,对名称空间的总结
2.1 全局作用域:全局存活,全局有效,伴随python运行始终,内置名称空间,全局名称空间
2.2 局部作用域:临时存活,局部有效,局部名称空间,只能在函数内用,调用完毕就结束

四、闭包函数

闭包函数 = 函数对象 + 函数嵌套定义 + 名称空间与作用域
1.闭函数:定义在函数内部的函数
def foo():
    def wrapper():
        pass
2.包函数:内部函数引用了一个外层函数的名字
def foo():
    x = 111  
    def wrapper(): 
        print(x)
    return wrapper # 千万不要加括号,加了括号就运行函数代码
f = foo()
print(f)

def func()
    x = 222
    f()
func()
# 闭包函数的作用:是一种为函数体传参的方案
# 为函数体传参的方案一:直接使用形参(首选)
def wrapper(x)
    print(x)
wrapper(11)
wrapper(22)
wrapper(33)
# 为函数体传参的方案二:闭包函数(括号内不能用参数时)
def outter(x):
    # x = 111
    def wrapper():
        print(x)
    return wrapper  # 不能加括号
wrapper = outter(111)  # 此处wrapper是变量
wrapper()   
posted @ 2021-07-01 14:26  Richer-J  阅读(79)  评论(0)    收藏  举报