函数的名称空间和作用域

一、函数是第一类对象

1.函数:

-定义:

​ 函数的名字就是函数的对象,函数名指向的函数的内存地址。

​ -有什么用?

​ -可以被引用

​ -可以被当作参数传入

​ -可以当作函数的返回值

​ -可以当作参数传入容器中

函数对象的应用:

	可以优雅的的取代if的分支
def index():
    '''
    无参函数
    '''
     print('from index')

print(index)  ##打印的是变量名的内存地址
>>>>>>
<function index at 0x0000015038D81EA0>



def index(l1):
    '''
    
   求列表的长度 
    '''
    print(len(l1))

l1 = [1,2,4,'afew']
index(l1)   ######调用函数 打印上面的print 的值 4
print(index(l1))####有index()都是要调用函数,打印上面的print   print(index())打印返                           回值,没有return 则返回none
>>>>>>>
4
4
None

1.函数名是可以被引用的

name = 'tank'
dsb = name
与上面的是类似的用法
f=def index():
    '''
    可以被引用
    '''
    print('from the index')
a = index
a()
>>>>>>
from the index

2.函数名可以当作参数传递

def foo(x,y,func):
    '''

    函数的名可以当作参数传递
    '''
    print(x,y)
    func()
def bar():
    print('from the bar')
foo(1,2,bar)
>>>>>>
1 2 
from the bar

3.函数名可以当作返回值使用,

传参的时候没有特殊要求,一定不要加括号,加括号当场执行

def index():
    '''
    
    函数名可以当作返回值用 
    '''
    print('from the index')
def func(a):
    return(a)
b = func(index)  ##### index  === return 中 的a    下main就是 index()
b()

>>>>>>>
from the index

4、函数名可以被当做容器类型的元素

def func():
    '''
    函数名可以作为容器类型的元素
    '''
    print('from ')

l1 = [1,2,func,func()]#####正常的python解释器的走向 从上到下 从左到右 定格写的                                        (1,2,func())   也可以调用func()的函数
f = l1[2]
print(f)
>>>>>>>
from   
<function func at 0x0000016D90FC1EA0> ####func的内存地址

购物车的一个程序

def register():
    print('register')
def login():
    print('login')
def shopping():
    print('shopping')
def pay():
    print('pay')
func_dic = {
    '1' : register,
    '2' : login,
    '3' : shopping,
    '4' : pay
}
def main():
    while True:
        print('''
        1、注册
        2、登录
        3、购物
        4、付款
        ''')
        choice = input('请输入对应的编号: ').strip()
        if choice == '5':
            break
        elif choice not in func_dic:
            continue
        else:
            func_dic[choice]()


main()

二、函数的嵌套

-函数的嵌套的定义:

​ -让内层函数封闭起来,不让外部直接调用。

-作用

​ -将功能并且小的功能,在函数内部调用,解决代码结构清晰问题。

def  index():
    ''''
    函数的嵌套
    '''
    print('from the world')
def func():
    index()
    print('from the world')
func()
>>>>>>
from the world
from the world


举例 2

def index(x, y):
    '''

   函数的嵌套
    '''
    if x > y:
        return x
    else:
        return y
print(index(index(index(1,2),3),6))
print(index(1,4))
>>>>>>>
6
4
举例3
def index(x, y):
    '''

   函数的嵌套
    '''
    if x > y:
        return x
    else:
        return y
def index_2(x,y,z,a):
    result = index(x,y)
    result = index(result, z)
    result = index(result,a)
    return result
print(index_2(1,2000,3,1000))
>>>>>>
2000
举例4
def index():
    '''
    
   函数的嵌套
    '''
    def home():
        print('well')
    home()
index()
>>>>>>
well

三、名称空间

什么是名称空间?
    存放名字的空间   名称空间是一个在内存种的空间
    如果你想访问一个变量值,必须先访问对应的名称空间,拿到名字和对应的内存地址的绑定关系
    名称空间的分类:
    1、内置名称空间:
        python提前给你的定义完的名字,就是存在内置名称空间
  
        print(input)
        >>>>>>
        <built-in function input>
    2、全局名称空间
        存放于文件级别的名字,就是全局名称空间
        if while for 内部定义的名字执行之后都存放于全局名称空间
        x = 1
        print(x)
    3、局部名称空间
        函数内部定义的所有名字都是存放与当前函数的内置名称空间
        
        生命周期:
    1、内置名称空间
        在python解释器启动的时候生效,关闭解释器的时候销毁
    2、全局名称空间
        当你启动当前这个py文件的时候生效,当前页面代码执行结束之后销毁,关闭python解释器时,彻底 销毁。
        x = 1   ####这个变量就是存放于全局名称空间
        def index():
            '''
            取x的值
            '''
            print(x)
        index()
            >>>>>>>>>>
               1
        Process finished with exit code 1 ####这个代表的是代码执行结束
    3、局部名称空间
        当你调用当前函数时生效,临时存活,函数调用结束后销毁。
        def index():
            x = 1     ###变量存放于局部的名称空间。
            print(x)
        index()
        >>>>>>
        1
    

下图是名称空间的图片

![img](file:///C:Users86187DocumentsTencent Files1341212001ImageGroup3K0L@[`%FVSWG}UW]6YQJLV.jpg)

四、名称空间的查找顺序

def index():#####index是全局变量名称空间
    '''
   print的值
    '''
    x = 1     ######x 是局部名称变量空间
    return x
print(index)#####没有执行函数,但是内存地址在定义函数的时候已经确定了,所以可以打印的出来

def foo():
    print(index) ######执行函数  打印的是index的内存地址
foo()
>>>>>>>>
<function index at 0x0000029F5B0A1EA0>
<function index at 0x0000029F5B0A1EA0>



######名称空间的查找顺序:######
    -加载顺序:内置--->全局---->局部
    -查找顺序:局部--->全局---->内置
# 函数内部使用的名字,在义阶段已经规定死了,与你的调用位置无关
如下图的是print(x)是函数内部使用的名字

x = 1
def index():
    '''

    查看局部变量
    '''
    print(x)
def wrapper():###这个是个局部的变量 不能赋给到上面的一层 
    x = 2
    index()
wrapper()
>>>>>
1
下面的例子
x = 1
def index():
    '''

    查看局部变量
    '''
    x = 3    #####局部从新有了名称空间,先用局部的 ,局部没有的话,才会去找全局的,wrapper属于是内层的嵌套,更低一级,也是不能操作的
    print(x)
def wrapper():
    x = 2
    index()
wrapper()
>>>>>
3

1111

x = 1
def inner():
    x = 2
    def wrapper():
        print(x)####上面一层的x =2是最后赋值的
    wrapper()
x = 111
inner()
>>>>>>>
2
下面的一个例子
x = 1
def inner():
    # x = 2
    def wrapper():
        print(x)
    wrapper()
x = 111
inner()
>>>>>>>
111

全局变量名称空间的一个例子

x = 1
def index():
     x = 2

print(x)
>>>>>>>
1     ######  这个的只是定义函数阶段,全局变量找值,如果没有就报错 不会去找局部变量的名称空间
在定义阶段的,提前给形参复制的操作就是默认值参数

x= 1
def index(arg = x):######arg 已经给赋值给1  下面的不会动
    '''
    看全局名空和局部明空的区别
    '''
    print(x)
    print(arg)#####只有掉用函数的时候,index(有值传入才可以把默认的arg = x,进行修改)
x = 2    #####     x被从新赋值给2
index()
>>>>>>>
2
1

另外一个例子
x = 1
def index():
    '''

    全局名称空间
    '''
    def wrapper(): 
        print(x)
    return wrapper#####return 在index函数的下方,所有返回的wrapper给了f,f =wrapper ,wrapper()执行wrapper的函数
f = index()
f()
>>>>>>
1


五、作用域的分类

作用域:
名称空间的作用范围

作用域的分类:
    1、全局作用域
        -全局可以调用的名字就存在于全局作用域
        -只要程序一直执行,永久存活,若程序结束,则销毁
         内置名称空间+全局名称空间
    2、局部作用域
        局部可以调用的名字就存放与局部作用域
          -局部的名称空间+局部的局部名称空间、
          -只要程序一直执行,调用函数时存活,结束时销毁。
        
        局部名称空间

global:声明全局变量(***)
nonlocal:在局部名称空间声明局部变量,在局部修改上层函数的变量(*)

只有可变类型可以在局部修改外部变量的值 (*****)

全局变量的举例
def index():
    # global x
    x = 2   ######x = 2 是局部变量名空  不能被全局的x(print(x))的调用
    print()
index()
print(x)
>>>>>>>>
  print(x)   
NameError: name 'x' is not defined
    
    修正后
def index():
    global x   ######声明了x为全局的变量名称空间
    x = 2
    print()
index()
print(x)
>>>>>>>
2

nonlocal 

def index():
    '''
    
    nonlocal  ####在局部的名称空间声明局部变量
    '''
    x = 1
    def func():
        nonlocal x
        x = 2
    func()
    print(x)###如果没有nonlocal  打印出来的结果是1
index()
>>>>>>>
2


x = 1
def func():

    def wrapper():
        global x    ####这个声明了修改x = 1 全局变量  所以打印结果x = 2
        x = 2
    wrapper()
    print(x)
func()
>>>>>>>>>
2


######只有可变类型可以在局部修改外部变量的值 (*****)

l1 = []
def index(a):
    '''
    
    可变的列表比较特殊 
    '''
    l1.append(a)
    #print(l1)
index(1)
print(l1)
>>>>>>>
[1]


局部变量的修改无法影响上层,上上层

def index():
    x = 1

    def index2():
        nonlocal x
        x = 2

    index2()
    print(x)####如果没有nonlocal 打印的结果就是1


index()
>>>>>>>>
2

局部变量的修改无法影响上层,上上层


x = 111
def index():
    x = 1

    def func2():
        x = 2

        def func():
            nonlocal x
            x = 3

        func()
        print(x)###因为在局部名称空间声明了局部变量,在局部修改上层函数的变量

    func2()
    print(x)


index()
print(x)
>>>>>>
3
1
1111

原文地址:https://www.cnblogs.com/bs2019/p/11851761.html