2019-07-10 函数的进阶(一)

一、函数对象

    函数是第一类对象:函数名指向的值可以被当做参数传递

    1.函数名可以被传递

def func():
    print('from func')
f = func      #函数名可以被传递,这里用一个变量名赋值
func()    #from func
print(f)    #这里打印的是函数的内存地址
f()       #f()等价于  func()

    2.函数名可以被当做参数传递给其他函数

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

def index(args):
    print(args)      #等价于print(func)   打印函数func内存地址
    args()        #运行函数func()  执行内部代码
    print('from index')
index(func)    #函数名func当做参数名传递到index函数中



#结果
#<function func at 0x0000001A50EE0E18>
#from func
#from index

    3.函数名可以被当做函数的返回值

def index():
    print('index')
def func():
    print('func')
    return index
res = func()   #返回值是  index
print(res)   #打印函数名index的内存地址
res()    #调用运行index()函数


#结果
#func
#<function index at 0x0000001DB2490E18>
#index

    4.函数名可以被当做容器类型的参数

def func():
    print('func')
print(func())     #func    None
l = [1,2,func,func()]  
print(l)



#结果
func
None
func      #为什么结果有这个,因为在l调用了函数func(),所以打印一个func
[1, 2, <function func at 0x0000009769AF0E18>, None]  

二、函数调用    (在一个函数内部调用其他函数,可以将复杂的逻辑简单化)

def index():
    func()
    print('index')

def func():
    print('func')

index()


#调用index()之后,func()已经被定义了,可以被调用

三、名称空间

    名称空间是什么:就是存放变量名和变量值的内存地址的绑定关系的地方

    名称空间的分类:

      1.内置空间名称:python解释器提前给你定义好的名字(已经存放在内置名称空间了)

          就是一些内置函数:比如   len()/max()....

      2.全局名称空间:文件级别的代码

      3.局部名称空间:函数体内创建的名字都属于局部名称空间  

def func():
    username = 'jason'    #这个username是局部名称空间
    print(username)
func()

  总结:生命周期

    内置名称空间:只要python解释器已启动立马创建   关闭python解释器的时候内置名称空间自动销毁(针对于python解释器)

    全局名称空间:只要你运行py文件的时候会自动创建   py文件程序运行结束自动销毁 (针对于py文件)

    局部名称空间:函数被调用的时候创建  函数结束就销毁(针对于函数的调用开始结束)

四、名称空间的查找顺序

  注意:先要确定好你当前在哪(在哪个空间)

      查找顺序    

      1.如果你现在在全局:   全局  >>>内置   (先从全局找再到内置)

      2.如果你现在在局部:局部>>全局>>内置(先从局部找再到全局再到内置)

  例题:

  局部命名空间:先定位要打印的len属于什么空间,因为它是在函数里面的变量,所以它是局部名称空间,先找局部变量,正好函数里面有一个变量名赋值,所以这个len就从这取值

len = '我是全局名称空间的len'
def func():
    len = '我是局部名称空间的len'
    print(len)
func()

  全局和局部:我们先来看红色的len,这个len在全局的位置,查找顺序先从全局开始,不会找到函数内部的局部。在全局里面已经有一个定义的len,所以用这个  '我是全局名称空间的len'。然后函数里面的len就和上面的一样了。

len = '我是全局名称空间的len'
def func():
    len = '我是局部名称空间的len'
    print(len)
print(len)  # 我现在站在的是全局的位置
func()

#结果
#我是全局名称空间的len
#我是局部名称空间的len

  局部:打印的x在局部位置,在本身函数没有,所以就往上一个找局部,找到有一个x。

def func():
    x = 1
    def index():
        print(x)  # 1
    return index

res = func()
x = 999
res()

  全局:如果把上一道题的局部x删掉,就要到全局里面找,找到x=999在函数调用之前已经定义了,最后结果就是999

def func():
    def index():
        print(x)  # 999
    return index

res = func()
x = 999
res()

  全局:x定位到局部,但是在inner里面找不到,outer里面也找不到,所以x是使用全局,后面的inner在哪里调用,x都是在全局找值

x=111
def outer():
    def inner():
        print('from inner',x)     #from inner 111
    return inner
f=outer()
def func():
    x=333
    f()
func()

  总结:函数在定义阶段就已经固定查找名字的顺序了,不会因为函数调用的位置改变而改变

五、作用域

  作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域

  全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用,全局有效

  局部作用域:局部名称空间、只能在局部范围生效

  

  global和nonlocal

    global:在局部修改全局的不可变数据类型

    在下面这个如果不是用global,后面x和username打印的全局的值,就是1,jason。如果你使用了global,改变了全局变量的值,在下面设置x = 999,username = 'egon',打印的值也是这个。

    

    nonlocal:局部修改局部(函数嵌套)

    如果没有加nonlocal,x在局部找值,x=1。nonlocal 修改了前面x的值,在打印的时候变成2

          

    总结:global:局部修改全局,如果有多个,用逗号隔开

          nonlocal:局部修改局部,如果有多个,用逗号隔开

原文地址:https://www.cnblogs.com/wangcuican/p/11165280.html