码迷,mamicode.com
首页 > 编程语言 > 详细

python之函数的进阶、闭包、装饰器

时间:2018-05-28 11:39:43      阅读:156      评论:0      收藏:0      [点我收藏+]

标签:全局   执行   opened   int   16px   ros   strong   登录   style   

本节内容:函数的进阶、闭包、装饰器

  1.名称空间

  2.作用域

  3.取值顺序

  4.函数的嵌套

  5.内置函数

  6.关键字

       7.函数的应用

       8.闭包

       9.装饰器

1、名称空间                                                                                                   

1.1 名称空间

当程序运行时,代码从上之下一次执行,他会将变量与值的关系存储在一个空间中,这个空间叫做名称空间,命名空间,全局名称空间。

技术分享图片

1.2 局部名称空间

当程序遇到函数时,他会将函数名存在内存中,函数体莫不关心。

当函数执行时,内存会临时开辟一个空间,存放函数体里面的代码(变量,代码等),

函数外面访问不到临时空间的内容,随着函数的执行完毕,临时名称空间会释放掉,

向这个临时开辟的空间叫临时名称空间,也叫局部名称空间。

  技术分享图片

1.3 Python中名称空间种类

    内置名称空间。

    全局名称空间。

    局部名称空间。

2、作用域                                                                                                       

2.1 全局作用域

    内置名称空间

    全局名称空间

2.2 局部作用域

    局部名称空间

2.3 加载顺序

内置名称空间 ---> 全局名称空间(当程序执行时) ---> 局部名称空间(当函数调用时)

3、取值顺序                                                                                                  

取值顺序:单向不可逆

局部名称空间(当函数调用时) -->全局名称空间(当程序执行时) -->内置名称空间

3.1 先从局部找

技术分享图片
name1 = oldboy
def func2():
    name1 = alex
    print(name1)
func2()
=====>输出
alex
View Code

3.2 再从全局找

技术分享图片
name1 = oldboy
def func2():
    print(name1)
func2()
=====>输出
oldboy
View Code

3.3 最后从内置空间找

技术分享图片
def func2():
    print(input)
func2()
=====>输出
<build-in function input>
View Code
4、函数的嵌套                                                        
技术分享图片
def func1():
    print(666)

def func2():
    func1()
    print(333)

def func3():
    func2()
    print(222)
print(111)
func3()
print(555)
=====>输出
111
666
333
222
555
==========
def func1():
    name = alex
    print(name)
    def func2():
        name1 = 太白
        print(333)
    print(444)
    func2()
func1()
=====>输出
alex
444
333
View Code

5、内置函数                                                                                                

5.1 globals()

返回一个字典,字典里面的内容是全局作用域的内容。

技术分享图片
name = alex
age = 1000
sex = 
def func1():
    name1 = oldboy
    age = 10000
func1()
print(globals())
print(locals())
=========>输出
None, name: alex, age: 1000, sex: , func1: <function func1 at 0x0000000001CF2E18>}
None, name: alex, age: 1000, sex: , func1: <function func1 at 0x0000000001CF2E18>}
View Code

5.2 locals()

返回一个字典,当前位置 的所有变量。

技术分享图片
def func1():
    name1 = oldboy
    age = 10000
    def func2():
        name2 = wusir
        age2 = 25
        print(globals())
        print(locals())
    func2()
func1()
=====>输出
None, func1: <function func1 at 0x0000000001D02E18>}
{age2: 25, name2: wusir}
View Code

6、关键字                                                                                                  

6.1 global

6.1.1 引用并改变一个全局变量

技术分享图片
count = 1
def func1():
    global count
    count = count + 1
    # count = count + 100
    print(count)
func1()
print(count)
=====>输出
2
2
View Code

6.1.2 在局部作用域声明一个全局变量

技术分享图片
def func1():
    global name
    name = alex
    print(name)
func1()
print(name)
=====>输出
alex
alex
View Code

6.2 nonlocal

1、不能操作全局变量

从哪层引用的该变量,从那层开始全部改变。

技术分享图片
def func1():
    count = 1
    def inner():
        nonlocal count
        count = count + 3
        print(count)
        def inner2():
           pass
    inner()
    print(count)
func1()
=====>输出
4
4
View Code
取值:引用而不是改变
取值是从小到大取值 LEGB
想改变上层空间的变量 要用到global nonlocal
2、对于可变的数据类型 list dict set 不用global nonlocal
技术分享图片
list = []
def func1():
    list.append(666)
func1()
print(list)
=====>输出
[666]
View Code

3、如果默认参数是一个可变的数据类型,那么他在内存中永远是一个

技术分享图片
def extendList(val,list=[]):
    list.append(val)
    return list
list1 = extendList(10)
print(list1=%s%list1)  
list2 = extendList(123,[])
print(list2=%s%list2)
list3 = extendList(a)
print(list3=%s%list3) 

print(list1=%s%list1)
print(list2=%s%list2)
print(list3=%s%list3)
=======>输出
list1=[10]
list2=[123]
list3=[10, a]
list1=[10, a]
list2=[123]
list3=[10, a]
View Code

7、函数名的应用                                                     

技术分享图片
def func1():
    print(666)
1 打印函数名
print(func1)  # <function func1 at 0x000000000258F9D8>

2 函数名可以作为容器类数据的元素
def func1():
    print(111)

def func2():
    print(222)

def func3():
    print(333)

l1 = [func1, func2, func3]
for i in l1:
    i()

3 函数名可以作为函数的参数

def func1():
    print(111)

def func2(x):
    print(x)
    x()
    print(222)

func2(func1)

4 函数名可以作为函数的返回值

def func1():
    return 111

def func2(x):  # x = func1
    print(222)
    return x

ret = func2(func1)  # func1
print(ret())
print(ret)
View Code

7.1 第一类对象

技术分享图片
def func3(x):
    print(x)
    return x

def func1():
    print(1111)
    return 111
f1 = func1
f2 = f1
f3 = f2
print(f3)
f3()
=========>输出
<function func1 at 0x00000000025120D0>
1111
View Code

8、闭包                                                                                                       

内层函数对外层函数非全局变量的引用,就叫做闭包。

技术分享图片
def wrapper():
    name = alex
    def inner():
        print(name)
    inner()
wrapper()
======>输出
alex
=======
name = alex
def wrapper():
    def inner():
        print(name)
    inner()
    print(inner.__closure__)  # None
wrapper()
=======>输出
alex
None
View Code

8.1 通过函数名.__closure__

技术分享图片
name = alex
def wrapper(x):
    x = name
    def inner():
        print(x)
    inner()
    print(inner.__closure__) 
wrapper(name)
=====>输出
alex
(<cell at 0x0000000001E16498: str object at 0x000000000049C110>,)
View Code
如果 python 解释器遇到了闭包,他有一个机制,这个闭包不会随着函数的结束而释放。
9、装饰器                                                                                                   
技术分享图片
import time
print(time.time()) 

def func1():
    time.sleep(0.3)
    print(非常复杂......)

start_time = time.time()
func1()
end_time = time.time()
print(此函数的执行效率%s %(end_time-start_time))
===========>输出
1527471870.8405445
非常复杂......
此函数的执行效率0.3000171184539795
==============
# 改版1:我要封装到一个函数中
import time
print(time.time()) 
def func1():
    time.sleep(0.3)
    print(非常复杂......)

def func2():
    time.sleep(0.3)
    print(特别复杂......)

func1()
func2()
========>输出
1527471978.33138
非常复杂......
特别复杂......
==============
# 改版2:被测试函数当参数传入,可以测试多个函数的执行效率
def timmer(f):
    start_time = time.time()
    f()
    end_time = time.time()
    print(此函数的执行效率%s %(end_time-start_time))

timmer(func1)
timmer(func2)
=================
改版3::测试函数执行效率的同时,不要改变原函数的调用方式。
def func1():
    time.sleep(0.3)
    print(非常复杂......)
def func2():
    time.sleep(0.3)
    print(特别复杂......)
# func1()
# func2()
def timmer(f):
    start_time = time.time()
    f()
    end_time = time.time()
    print(此函数的执行效率%s % (end_time - start_time))
f1 = func1
func1 = timmer  #
func1(f1)  # timmer(func1)
=================
改版4::改版3虽然大体上满足了我的要求,但是增加两行代码,
而且多了参数,不好,继续改,尽量不添加其他代码,而且做到调用时一模一样
最简单的装饰器。
def func1():
    time.sleep(0.3)
    print(非常复杂......)
def func2():
    time.sleep(0.3)
    print(特别复杂......)
# func1()
# func2()

def timmer(f):  # f = func1 函数名
    def inner():
        start_time = time.time()
        f()
        end_time = time.time()
        print(此函数的执行效率%s % (end_time - start_time))
    return inner

func1 = timmer(func1)  # inner
func2 = timmer(func2)  # inner
func1()  # inner()
func2()

========================
改版5::改版4每次测试一个函数的执行效率时,都需要加一行 func1 = timmer(func1)代码,麻烦
python提出了一个语法糖 @。


def timmer(f):  # f = func1 函数名
    def inner():
        start_time = time.time()
        f()
        end_time = time.time()
        print(此函数的执行效率%s % (end_time - start_time))
    return inner

@timmer  # func1 = timmer(func1)  inner
def func1():
    time.sleep(0.3)
    print(非常复杂......)

func1()  # inner()
========================
改版6:被装饰的函数肯定要有参数的,你现在不能满足,解决这个问题。
被装饰的函数带参数的装饰器
def timmer(f):  # f = func1 函数名
    def inner(*args,**kwargs):  # args = (1,2),kwargs {sex:‘nv‘,name:‘alex‘}
        start_time = time.time()
        f(*args,**kwargs)  # f(1,2,,sex=‘nv‘,name=‘alex‘)
        end_time = time.time()
        print(此函数的执行效率%s % (end_time - start_time))
    return inner

@timmer  # func1 = timmer(func1)  inner
def func1(a,b):
    time.sleep(0.3)
    print(a,b)
    print(非常复杂......)


@timmer  # func1 = timmer(func1)  inner
def func2(a,b,name,sex=man):  # f(1,2,,sex=‘nv‘,name=‘alex‘)
    time.sleep(0.3)
    print(a,b,sex,name)
    print(非常复杂......)

func2(1,2,sex=nv,name=alex)  # inner()
====================
改版7:被装饰的函数肯定要有返回值的,解决这个问题。
被装饰的函数带参数且有返回值的装饰器

def timmer(f):  # f = func2 函数名
    def inner(*args,**kwargs):  # args = (1,2),kwargs {sex:‘nv‘,name:‘alex‘}
        start_time = time.time()
        ret = f(*args,**kwargs)  # f(1,2,,sex=‘nv‘,name=‘alex‘)
        end_time = time.time()
        print(此函数的执行效率%s % (end_time - start_time))
        return ret
    return inner
@timmer  # func1 = timmer(func1)  inner
def func2(a,b,name,sex=man):  # f(1,2,,sex=‘nv‘,name=‘alex‘)
    time.sleep(0.3)
    print(a,b,sex,name)
    print(非常复杂......)
    return 666

print(func2(1,2,sex=nv,name=alex))  # inner()

def timmer(f):
    def inner(*args,**kwargs):
        start_time = time.time()
        ret = f(*args,**kwargs)
        end_time = time.time()
        print(此函数的执行效率%s % (end_time - start_time))
        return ret
    return inner
@timmer
def func2(a,b,name,sex=man):
    time.sleep(0.3)
    print(a,b,sex,name)
    print(非常复杂......)
    return 666

ret1 = func2(1,2,sex=nv,name=alex)
print(ret1)


def wrapper(f):
    def inner(*args,**kwargs):
        """被装饰函数执行之前的操作"""

        ret = f(*args,**kwargs)
        """被装饰函数执行之后的操作"""
        return ret
    return inner
View Code
装饰器 本质就是闭包
装饰器根本作用:在不影响原函数执行的基础上,增加一些额外的功能登录认证,打印日志等等。

python之函数的进阶、闭包、装饰器

标签:全局   执行   opened   int   16px   ros   strong   登录   style   

原文地址:https://www.cnblogs.com/bowen-li/p/s187010.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!