函数嵌套及作用域

一、函数对象

函数是第一类对象:函数的内存地址(即函数名)可以像一个变量值一样去使用

1、变量值可以被引用,例如 x = 1,y = x

def foo():
    print('from foo')

f = foo     # 变量值(函数名)被引用
print(f)
f()

2、变量值可以当作参数传给另外一个函数

def foo():
    print('from foo')

def bar(x):
    print(x)
    x()

bar(foo)    # 函数名当作参数传给另外一个函数

3、变量值可以当作函数的返回值

def foo():
    print('from foo')

def func(x):
    return x

f = func(foo)   # 函数名当作函数的返回值
print(f)

4、变量值可以当作容器类型的元素

def foo():
    print('from foo')

li = [foo, ]    # 函数名当作列表的元素
print(li)
li[0]()

dic = {'1': foo}   # 函数名当作字典的元素
print(dic)
dic['1']()

二、函数嵌套

1、函数的嵌套定义:在函数内又定义了其他函数

def func():
    def foo():
        print('from foo')

    foo()
    x = 1
    print(x)

func()

2、函数嵌套调用:在一个函数内部又调用其他函数

# 比较四个数的大小
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))
# 计算圆的面积和周长

from math import pi

def circle(radius, action):
    def cal_perimeter():
        return 2 * pi * radius

    def cal_area():
        return pi * (radius ** 2)

    if action == 1:
        res = cal_perimeter()
    elif action == 2:
        res = cal_area()

    return res

res = circle(5, 1)
print(res)
计算圆的面积和周长

三、名称空间

1、定义:存放名字与值的内存地址绑定关系的地方

2、名称空间分为三大类:

  内置名称空间:存放的是 Python 解释器自带的名字,Python 解释器的启动则产生,关闭则销毁

  全局名称空间:创建的存储 “变量名与值的关系” 的空间,是在顶级定义的,Python程序执行时产生,程序执行完毕后则销毁

  局部名称空间:在函数的运行中开辟的临时的空间,是在函数内部定义的,在函数调用时临时产生,调用完毕后则销毁

三种名称空间的加载顺序和取值顺序:

加载顺序:内置(程序运行前加载)-->全局(从上到下顺序加载进来的)-->局部(调用的时候加载)--->内置

取值:

  当前在局部名称空间:局部 ---> 全局 ---> 内置

  当前在全局名称空间:全局 ---> 内置

使用:全局不能使用局部的,局部的可以使用全局的

四、作用域:就是作用范围

1、全局作用域

定义:包含内置与全局名称空间的名字

特点:在整个程序的任意位置都能被引用,全局有效

2、局部作用域

定义:包含局部名称空间的名字

特点:临时存活,只能在局部范围内生效

作用域关系是在函数定义阶段就已经固定死了,与调用位置无关!!

# 示范一:
def f1():
    print(xxx)
xxx = 111

def f2():
    xxx = 222
    # 不管f1在哪调用, 都是去找定义阶段的作用域关系,
    # 与上面的xxx=222没有任何关系
    f1()

f2()    # 执行结果:111
# 示范二:
xxx = 111
def f1():
    '''
    函数定义阶段只检测语法, 不执行代码
    这里先输出xxx, 先从局部找xxx, 找到了x=222但是却定义在了输出的下面
    语法上这种写法是错误的
    '''
    print(xxx)
    xxx = 222

f1()    # 执行结果报错

五、闭包函数

闭:封闭,指的是该函数定义一个内部函数

包:该内部函数包含了对外层函数作用域中变量的引用 

def outter():
    x = 1
    def inner():
        print("from inner", x)
    return inner

f = outter()    # 通过外部函数拿到了内部函数的地址

def foo():
    print(f)
    f()

foo()

为函数体传值的两种方式:

  def foo():

    print('hello %s' %name)

方式一:直接以参数的形式传入

def foo(name):
    print("hello %s" %name)
    
foo('qiu')
foo('qiu')
foo('qiu')

这种方式要想多次传值,每次都要手动添加参数

方式二:闭包含数

def outter(name):
    def foo():
        print("hello %s" %name)
    return foo

f = outter('qiu')
f()
f()
f()

要想多次传值只需要多次调用函数即可

应用:获取一个网页的信息

# 解决方案一: 以参数的形式传入

def get(url):
    response = requests.get(url)
    if response.status_code == 200:
        print(response.text)

# 要想多次获取信息只能多次传入
get('https://www.baidu.com')
get('https://www.cnblogs.com')
# 解决方案二: 闭包函数无需多次传入

def outter(url):
    def get():
        response = requests.get(url)
        if response.status_code == 200:
            print(response.text)

    return get

baidu = outter('https://www.baidu.com')
cnblogs = outter('https://www.cnblogs.com')

# 要想多次获取只需多次调用
baidu()
baidu()
cnblogs()
原文地址:https://www.cnblogs.com/qiuxirufeng/p/9709762.html