Python开发-函数对象、函数嵌套、名称空间与作用域、装饰器

一:函数对象

函数是一类对象,即函数可以当作数据传递

1 可以被引用
2 可以当作参数传递
3 返回值可以是函数
3 可以当作容器类型的元素

二:函数嵌套

函数嵌套的调用

 

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

def max4(a,b,c,d):
    res1=max(a,b)
    res2=max(res1,c)
    res3=max(res2,d)
    return res3
print(max4(1,2,3,4))

函数嵌套的定义

def f1():
    def f2():
        def f3():
            print('from f3')
        f3()
    f2()

f1()

 

三:命称空间与作用域

什么是名称空间?

  名称空间:存放名字的地方,三种名称空间:局部名称空间--->全局名称空间--->内置名称空间(名字查找顺序)

名称空间的加载顺序

1、python解释器先启动,因而首先加载的是:内置名称空间

2、执行python文件,然后以文件为基础,加载全局名称空间

3、在执行文件的过程中如果调用函数,则临时产生局部名称空间

作用域

#1、作用域即范围
        - 全局范围(内置名称空间与全局名称空间属于该范围):全局存活,全局有效
      - 局部范围(局部名称空间属于该范围):临时存活,局部有效
#2、作用域关系是在函数定义阶段就已经固定的,与函数的调用位置无关,如下
x=1
def f1():
    def f2():
        print(x)
    return f2
x=100
def f3(func):
    x=2
    func()
x=10000
f3(f1())

#3、查看作用域:globals(),locals()


LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__
locals 是函数内的名字空间,包括局部变量和形参
enclosing 外部嵌套函数的名字空间(闭包中常见)
globals 全局变量,函数定义所在模块的名字空间
builtins 内置模块的名字空间

注意:一个在函数内部赋值的变量仅能在该函数内部使用(局部作用域),在所有函数之外赋值的变量,可以在程序的任何位置使用(全局作用域)

注意:函数执行时,优先读取局部变量,能读取全局变量,无法对全局变量重新赋值,但是对于可变类型可以对内部元素进行操作

代码示例:

lis = [1,2,3]
def append_num():
    lis.append(4)
    print(lis)
append_num()

 

四: global与nonlocal关键字

global关键字:将局部变量声明为全局变量

闭包函数(nonlocal语句)

  内部函数包含对外部作用域而非全局作用域的引用

提示:之前我们都是通过参数将外部的值传给函数,闭包提供了另外一种思路

 1         def counter():
 2             n=0
 3             def incr():
 4                 nonlocal n
 5                 x=n
 6                 n+=1
 7                 return x
 8             return incr
 9 
10         c=counter()
11         print(c())
12         print(c())
13         print(c())
14         print(c.__closure__[0].cell_contents) #查看闭包的元素

闭包函数的意义和应用

闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域

应用领域:延迟计算(原来我们是传参,现在我们是包起来)

1     from urllib.request import urlopen
2 
3     def index(url):
4         def get():
5             return urlopen(url).read()
6         return get
7 
8     baidu=index('http://www.baidu.com')
9     print(baidu().decode('utf-8'))

五: 装饰器

什么是装饰器:闭包函数的一种应用场景

装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。 强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式 装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能

装饰器的使用:    知识储备—高阶函数+函数嵌套+闭包

1,无装饰器情景

import time
def timmer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time=time.time()
        print('run time is %s' %(stop_time-start_time))
        return res
    return wrapper

@timmer
def foo():
    time.sleep(3)
    print('from foo')
foo()

2,有装饰器情景

def auth(driver='file'):
    def auth2(func):
        def wrapper(*args,**kwargs):
            name=input("user: ")
            pwd=input("pwd: ")

            if driver == 'file':
                if name == 'egon' and pwd == '123':
                    print('login successful')
                    res=func(*args,**kwargs)
                    return res
            elif driver == 'ldap':
                print('ldap')
        return wrapper
    return auth2

@auth(driver='file')
def foo(name):
    print(name)

foo('egon')

六:装饰器的语法

被装饰函数的正上方,单独一行
@deco1
@deco2
@deco3
def foo():
pass

foo=deco1(deco2(deco3(foo)))

七:装饰器补充---wraps

from functools import wraps

def deco(func):
    @wraps(func) #加在最内层函数正上方
    def wrapper(*args,**kwargs):
        return func(*args,**kwargs)
    return wrapper

@deco
def index():
    '''哈哈哈哈'''
    print('from index')

print(index.__doc__)

八:叠加多个装饰器

 叠加多个装饰器

1. 加载顺序(outter函数的调用顺序):自下而上

2. 执行顺序(wrapper函数的执行顺序):自上而下

代码示范

def outter1(func1): #func1=wrapper2的内存地址
    print('加载了outter1')
    def wrapper1(*args,**kwargs):
        print('执行了wrapper1')
        res1=func1(*args,**kwargs)
        return res1
    return wrapper1

def outter2(func2): #func2=wrapper3的内存地址
    print('加载了outter2')
    def wrapper2(*args,**kwargs):
        print('执行了wrapper2')
        res2=func2(*args,**kwargs)
        return res2
    return wrapper2

def outter3(func3): # func3=最原始的那个index的内存地址
    print('加载了outter3')
    def wrapper3(*args,**kwargs):
        print('执行了wrapper3')
        res3=func3(*args,**kwargs)
        return res3
    return wrapper3



@outter1 # outter1(wrapper2的内存地址)======>index=wrapper1的内存地址
@outter2 # outter2(wrapper3的内存地址)======>wrapper2的内存地址
@outter3 # outter3(最原始的那个index的内存地址)===>wrapper3的内存地址
def index():
    print('from index')

print('======================================================')
index()

示范代码

图解

 

 

  
posted @ 2020-02-21 15:12  赖正华  阅读(87)  评论(0编辑  收藏  举报