013.Python之函数嵌套、名称空间与作用域、闭包函数

一、函数嵌套

(一)什么是函数嵌套

在一个函数内又定义了另外一个函数。

def f1():
    def f2():
        print("from f2")

    f2()
    x = 1111
    return x

f1()  # from f2
print(f1())  # from f2  函数运行时输出的值
             # 1111  函数的返回值

===============================================================================
def f1():
    def f2():
        print('from f2')
    return f2

res=f1()
print(res)  # <function f1.<locals>.f2 at 0x000002EB71159040>   f2的内存地址
res()   # from f2

===============================================================================
import math

def circle(radius,mode):
    def perimiter(radius):
        return 2 * math.pi * radius

    def area(radius):
        return math.pi * (radius ** 2)
    if mode == 1:
        return perimiter(radius)
    elif mode == 2:
        return area(radius)

print(circle(18,1))  # 113.09733552923255
print(circle(18,2))  # 1017.8760197630929

(二)函数嵌套的调用

在调用一个函数的过程中又调用了其他函数。

def max2(x, y):
    if x > y:
        return x
    else:
        return y


def max4(a, b, c, d):
    res1 = max2(a, b)
    res2 = max2(res1, c)
    res3 = max2(res2, d)
    return res3


print(max4(1,2,3,4))  # 4

二、名称空间与作用域

(一)名称空间

名称空间就是存放名字的地方

1.内置名称空间

存放的是python解释器自带的名字,如len、print、input等。

生命周期:解释器启动则创建,解释器关闭就销毁。

2.全局名称空间

内置以及函数内的名字之外的名字都存放于全局名称空间中。

生命周期:运行顶级代码/主流水线则创建,顶级代码/主流水线结束则销毁。

# foo = 内存地址
def foo():  # foo本身也是全局的
    z = 111

    # f1=内存地址
    def f1():
        pass

if True:    # if语句是全局的
    aaa = 33

3.局部名称空间

函数内的名字。

生命周期:函数调用时则创建,函数调用完毕则立即销毁。

def f1(x, y):
    z = 3
    def f2():
        m=444
        n=5555
    f2()

f1(1, 2)
print(f1(1, 2))  # None 没有返回值,默认None

(二)名称空间名字的查找顺序

查找顺序:基于当前所在的位置向上查找。

# 局部-》外层套的局部-》外层套的局部-》....-》全局-》内置

# 示范1:站在全局进行查找
input = 333

def f1():
    input = 444

f1()
print(input)  # 333
# 示范2:站在局部进行查找

def f1():
    # input = 4444
    print(input)

input = 333

f1()  # 333

def f1():
    input = 4444
    print(input)

input = 333

f1()  # 4444
# 示范3
# 3.1
def f1():
    input = 444
    print(input)

def f2():
    input = 555
    print(input)

input = 333

f1()  # 444
f2()  # 555

# 3.2
def f1():
    input = 444
    print(input)

def f2():
    # input = 555
    print(input)

input = 333

f1()  # 444
f2()  # 333

# 3.2
def f1():
    input = 444
    print(input)

def f2():
    # input = 555
    print(input)

# input = 333

f1()  # 444
f2()
# 示范4:
# 示范4.1:
def f1():
    input = 444
    def inner():
        input = 555
        print(input)
    inner()
input = 333
f1()  # 555

# 示范4.2:
def f1():
    input = 444
    def inner():
        # input = 555
        print(input)
    inner()
input = 333
f1()  # 444


# 示范4.3:
def f1():
    # input = 444
    def inner():
        # input = 555
        print(input)
    inner()
input = 333
f1()  # 333

# 示范4.4:
def f1():
    # input = 444
    def inner():
        # input = 555
        print(input)
    inner()
# input = 333
f1()  # <built-in function input>
# 强调:名称空间的"嵌套关系"是函数定义阶段、也就是检测语法的时候就确定的,与调用为无关。
x = 111

def f1():
    print(x)

def f2():
    x = 222
    f1()

f2()  # 111

# 示范5:

def f3():

    print(x)
    x = 33333

x=222
f3()   # UnboundLocalError: local variable 'x' referenced before assignment
# 定义函数的时候,print(x)中x是局部作用域中的x,但是在调用的时候,x还没定义,也不能向上查找,所以报错,无法执行。

(三)作用域

1.全局作用域

# 全局作用域:内置名称空间、全局名称空间
#       全局存活、全局有效

2.局部作用域

# 局部作用域:局部名称空间
#       临时存活,局部有效

(四)函数的参数传递都是值拷贝

# 示范1:对全局定义的不可变类型,不可以在函数内直接修改
x = 10

def func(a): # a=10的内存地址
    a = 123

func(x) # x=10的内存地址

print(x)  # 10
# 示范2:对全局定义的可变类型,可以在函数内直接修改
x = []

def func(a): # a=列表的内存地址
    a.append(11111)
    # a=123

func(x) # x=列表的内存地址

print(x)  # [11111]
# 示范3:在函数内修改全局的不可变类型
x = 10
l = []

def func():
    global x
    x = 666
    l.append(1111)

func()
print(x)  # 666
print(l)  # [1111]
# 示范4:nonlocal(了解)
x = 10
def f1():
    x=11
    def f2():
        # global x
        nonlocal x
        x=66666
    f2()
    print("f1内的x===》",x)


f1()  # f1内的x===》 66666
print(x)  # 10

三、闭包函数

(一)什么是闭包函数

闭包函数,即函数对象+函数嵌套定义+名称空间与作用域。

闭:指的是定义函数内的函数。

包:指的内函数引用了外函数的变量。

def outter():
    x = 1111

    def inner():
        print(x)

    return inner  # 千万不要加括号

f = outter()
# print(f)  # <function outter.<locals>.inner at 0x000001ACE6E79040>

def f3():
    x=222222
    f()

f3()  # 1111

(二)为函数体代码传参的两种方式

1.方式一:直接通过参数的方式传入

def func(x):
    print(x)

func(1)
func(2)
func(3)

2.方式二:通过闭包函数传入

def outter(x):
    # x = 2

    def func():
        print(x)

    return func  # 一定不要加括号

f1 = outter(1)
f2 = outter(2)
f3 = outter(3)

f1()
f2()
f3()
原文地址:https://www.cnblogs.com/huluhuluwa/p/13155353.html