函数对象

Python-12

@(Python)

一、函数对象

  • 函数是第一类对象,意思是函数可以被当做数据处理
  • 函数对象:就是函数不带括号
  • 函数对象,可以将定义在函数内的函数,通过return返回值,返回到全局中使用,从而打破函数的层级限制
  • Python中一切皆对象

funcfunc()的区别

  • func()是函数的返回值
  • func函数名记录了值的内存地址(记录了值的内存地址,相当于连接函数名和值的线),函数名就是函数的内存地址
  • print(func)打印的是func函数名记录的值的内存地址
  • print(func())打印的是func函数的返回值

Alt text

① 函数名可以被用来引用(赋值给一个变量)

# func是一个函数
y=x
f=func
print(f)   # 就相当于print(func)
f()   # f()就相当于func()调用函数

② 函数名当做参数传给一个函数

Alt text

③ 函数名可以当做函数的返回值

Alt text

④ 函数名可以当做容器类型的元素

可以把函数的内存地址(或理解为函数名的内存地址),当做元素

Alt text

利用函数名为容器类型的元素,来调用函数

# 取款
def qk():
    print('取款成功')

# 转账
def zz():
    print('转账成功')
# 支付
def zf():
    print('支付成功')


func_dict={
    '1':qk,
    '2':zz,
    '3':zf,
}

while True:
    msg='''
    1. 取款
    2. 转账
    3. 支付
    4. 退出   
    '''
    print(msg)
    func_num=input('输入数字>>')
    if func_num == '4' : break
    if func_num not in func_dict:
        print('不在范围')
        continue
    func_dict[func_num]()

二、函数的嵌套

1. 函数的嵌套定义

  • 函数的嵌套是在函数中再定义函数
  • 在函数内中定义的函数,只能在这个函数内使用(一般情况下)
def func1():
    def func2():
        print('函数2')
  • 通过函数嵌套,将一个大功能的小功能嵌套进去,不同的功能汇聚到一起,类似于封装成一个工具箱
  • 例子:利用函数嵌套和函数对象当做容器元素,来写出计算圆面积和周长的功能
from math import pi    # 计算圆的公式需要调用
def yuan(banjing,action):
    def mianji():
        return pi * (banjing ** 2)
    def zhouc():
        return pi * banjing * 2
    if action == 'mianji':
        return mianji()    # 这是yun函数的返回值
    elif action == 'zhouc':
        return zhouc()

func1=input('半径>>')
func1=int(func1)
func2=input('计算类型>>')

print(yuan(func1,func2))   # 也可以使用默认形参固定一个常用的类型

2. 函数的嵌套调用

  • 使用函数嵌套,在调用一个函数时,也调用了其他函数
  • 如果一个功能可以被重复调用,就可以单独做成一个功能,使用其他函数再调用

Alt text

三、名称空间与作用域

1. 名称空间

  • 专门用来存名字的空间(变量名、函数名等的内存地址)
  • 名称空间,是存放名字和值绑定关系的地方

① 内置名称空间

  • 内置命名空间:Python解释器自带的名字
  • 生命周期:在解释器启动时生效,在解释器关闭时失效

② 全局名称空间

  • 全局名称空间:除了内置和局部空间外,其余都是全局名称空间
  • 全局名称空间,是在文件执行时产生的(顶头写的代码使用的就是全局名称空间)
  • 生命周期:在文件执行时生效,在文件执行完毕后失效

③ 局部名称空间

  • 存放函数调用期间函数体产生的名字,即函数内定义的名字
  • 生命周期:执行文件时,只有被调用了才会临时生效,在函数执行完毕后失效,自动释放

内置、全局、局部名称空间的加载顺序

  • ① 内置名称空间--->② 全局名称空间--->③ 局部名称空间

内置、全局、局部名称空间的查找顺序

  • ① 局部名称空间--->② 全局名称空间--->③ 内置名称空间
  • 基于当前位置,然后按顺序找

Alt text
Alt text

2. 作用域

  • 作用域就是名称空间的作用的范围,是对名称空间的再分类

① 全局作用域

  • 全局作用域:就是全局作用范围,包括:内置名称空间和全局名称空间
  • 全局有效:内置命名空间和全局命名空间
  • 全局存活:从程序开始存活,一直到程序的结束

② 局部作用域

  • 局部作用域:就是局部作用范围,包括:局部命名空间
  • 局部有效,临时存活

  • 作用域关系是在函数定义阶段就固定好了,但凡要调用函数就需要去函数的定义阶段找作用域关系

Alt text

x=10
def func1():
    print(x)

x=10000000000000000000000
def func2():
    x=11111111111
    func1()

func2()   # 以调用为分隔符,往前找

Alt text

Alt text

x=10
def func1():
    x=777777777777777777  # 先找局部空间,再找全局空间,全局空间有多个找上面最近的
    print(x)

x=10000000000000000000000
def func2():
    x=11111111111
    func1()

func2()   # 以调用为分隔符,往前找

③ 作用域的应用:

  • 打破层级限制,利用return将函数名转到全局,再调用

Alt text
Alt text

def f1():
    def inner():
        print('from inner')
    return inner

f1()() # f1()得到的是return的值,相当于inner,f1()() == inner()

# 或者

f=f1()
f()   # 相当于f1()()

Alt text

def f1():
    x=1
    def inner():
        print('from inner',x)
    return inner

f=f1()   # 相当于f=inter

def bar():
    x=11111111111111
    f()   # 相当于inter()

bar()
  • 说明:回到定义阶段,按照先局部,后全局的顺序找,如果局部没有才找全局,如果有多个全局,就以调用函数为分隔线,往上找最近的

  • 在函数体内,改全局的东西,需要使用global x,比如global xx拿到全局用,同代码段往下找最后一个
  • 但是尽量不要改全局,尽量做成独立的功能,对其他无影响
x=1
def foo():
    global x
    x=111

foo()
print(x)
  • nonlocal会往本函数体外层找,往上找最近的,但是还是在大的函数内,找到就改,找不到就报错
x=1
def f1():
    def f2():
        x=2222222            # 找到的内容
        def f3():
            nonlocal x
            x=111111111111   # 要改成什么
        f3()
        print(x)   # 打印这一层的,看nonlocal是后生效
    f2()

f1()

Alt text

  • 在局部如果想要修改全局的可变类型,不需要借助任何声明,可以直接修改,比如可以改字典,列表等
  • 在局部如果想要修改全局的不可变类型,需要借助global声明,声明为全局的变量就可以直接修改

Alt text

原文地址:https://www.cnblogs.com/itone/p/9443649.html