python3 闭包、类的装饰器,元类

 1.闭包

  (1)一个函数里面还嵌套了函数;

  (2)包含了对外部函数作用域中变量的引用

      内部函数包含对外部作用于而不是全局作用域变量的引用,那么我们就称该内部函数为闭包函数;

      作用:能够引用外部函数的变量,并且可以保证外部函数的变量控制在一个局部作用域;

      和 函数还是有区别的。

def test():
    sum=100
    #  在函数内部定义一个桉树,并且里面的函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包
    def test1(y):
        return sum+y
    #  这里返回的就是闭包的结果
    return test1
t=test()
#  这里的5其实是给参数y
print(t(5))


#####################
105
View Code

  nonlocal访问、修改外部函数的局部变量(python3)

  是闭包内部变量的声明:声明变量不是局部变量,这样下方的代码可以对外部函数传入的变量进行修改

x=300
def test3():
    x=200
    print("————2————:%d" %x)
    def test4():
        nonlocal x
        print("————3————:%d" %x)
        x=100
        print("————4————:%d" %x)
    return test4
print("——1——%d" %x)
print("我是华丽分割线==========================")
t1=test3()
t1()




##################
——1——300
我是华丽分割线==========================
————2————:200
————3————:200
————4————:100
View Code

   闭包和函数的区别:(面试经常问)

  原文:https://blog.csdn.net/gymaisyl/article/details/83019368 

    闭包:在闭包中,既有函数,又有数据,而且数据是闭包里面独有的数据,与外界无影响;

    函数:函数中,需要使用的全局变量,在一定程度上是受到限制的,因为全局变量不仅仅是一个函数使用,其他的函数也可能会使用到,一旦修改会影响到其他函数使用全局变量,所以全局变量不能随便修改从而在函数的使用中受到一定局限性。

2.装饰器 

def outer(func):
    def inner():
        print('我是 inner函数!!!')
    return inner
    #return inner()  这两种的差别
def foo():
     print('我是原始函数!!!')

outer(foo)
outer(foo())
# 函数名: foo、outer、inner
# 函数体:函数的整个代码结构
# 返回值: return后面的表达式
# 函数的内存地址:id(foo)、id(outer)等等
# 函数名加括号:对函数进行调用,比如foo()、outer(foo)
# 函数名作为参数: outer(foo)中的foo本身是个函数,但作为参数被传递给了outer函数
# 函数名加括号被当做参数:其实就是先调用函数,再将它的返回值当做别的函数的参数,例如outer(foo())
# 返回函数名:return inner
# 返回函数名加括号:return inner(),其实就是先执行inner函数,再将其返回值作为别的函数的返回值。
View Code

  写代码要遵循开放封闭原则,简单来说,已经实现的功能代码内部不允许被修改,但外部可以被扩展。

  上面的这句话就是说明使用装饰器的原因了。我自己认为的。

  装饰器本质就是一个函数去装饰另外一个函数,可以在不修改原有代码的情况下,为被装饰的对象增加新的功能或者附加限制条件或者帮助输出;

  高阶函数+嵌套=装饰器;

  装饰器的存在就是给另外一个函数添加功能,不能修改被装饰函数的源代码;并且不能修改被装饰函数的调用方式。

  一个理解:

    函数即"变量"——函数名相当于变量名,函数体也就是变量值。

def outer(func):
    def inner():
        print("认证成功!")
        result = func()
        print("日志添加成功")
        return result
    return inner

@outer
def f1():
    print("业务部门1数据接口......")

f1()

程序开始运行,从上往下解释,读到def outer(func):的时候,发现这是个“一等公民”函数,于是把函数体加载到内存里,然后过。

读到@outer的时候,程序被@这个语法糖吸引住了,知道这是个装饰器,按规矩要立即执行的,于是程序开始运行@后面那个名字outer所定义的函数。

程序返回到outer函数,开始执行装饰器的语法规则。规则是:被装饰的函数的名字会被当作参数传递给装饰函数。装饰函数执行它自己内部的代码后,会将它的返回值赋值给被装饰的函数。原来的f1函数被当做参数传递给了func,而f1这个函数名之后会指向inner函数。

看看以下两种区别:
def outer(func):
    def inner():
        print("认证成功!")
        result = func()
        print("日志添加成功")
        return result
    return inner

@outer
def f1():
    print("业务部门1数据接口......")

f1()

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

def outer(func):
    print("认证成功!")
    result = func()
    print("日志添加成功")
    return result

@outer
def f2():
    print("业务部门1数据接口......")
View Code

  简单装饰器:

   对没有参数,没有返回值的函数进行装饰:   

def set_func(func):
    def call_func():
        print("---这是添加功能1----")
        print("---这是添加功能2----")
        func()
    return call_func

@set_func
def test():
    print("----这个是主功能---")

test()

######################
---这是添加功能1----
---这是添加功能2----
----这个是主功能---
View Code

     装饰器简单运用:

import time
def set_func(func):
    def call_func():
        start_time=time.time()
        func()
        stop_time=time.time()
        print("alltime:%f" % (stop_time-start_time))
    return call_func
@set_func   #等价于test=set_func(test)
def test():
    print("---test---")
    time.sleep(2)

test()

######################
---test---
alltime:2.000812
View Code

     对有参数,无返回值的函数进行修饰:

def set_func(func):
    def call_func(num):
        print("---这是添加功能1----")
        print("---这是添加功能2----")
        func(num)
    return call_func

@set_func
def test(num):
    print("----这个是主功能%d---" %num)

test(5)


---这是添加功能1----
---这是添加功能2----
----这个是主功能5---
View Code

    同一个装饰器对多个函数进行装饰:

def set_func(func):
    def call_func(num):
        print("---这是添加功能1----")
        print("---这是添加功能2----")
        func(num)
    return call_func

@set_func
def test1(num):
    print("----这个是主功能%d---" %num)

@set_func
def test2(num):
    print("----这个是主功能%d---" %num)

test1(5)
test2(20)



#########################
---这是添加功能1----
---这是添加功能2----
----这个是主功能5---
---这是添加功能1----
---这是添加功能2----
----这个是主功能20---
View Code

  注意: 

    装饰器在调用函数之前,已经被python解释器执行了,所以要牢记 当调用函数之前 其实已经装饰好了,正常调用就可以了。

  对使用不定长参数的函数进行修饰:

def set_func(func):
    def call_func(num,*args,**kwargs):
        print("---这是添加功能1----")
        print("---这是添加功能2----")
        func(num,*args,**kwargs)#  拆包
    return call_func

@set_func
def test(num,*args,**kwargs):
    print("----这个是主功能%d---" %num)
    print("----这个是主功能---" ,args)
    print("----这个是主功能---" ,kwargs)

test(20)
test(100,200)
test(20,50,300,mm="小猪猪")

#########
---这是添加功能1----
---这是添加功能2----
----这个是主功能20---
----这个是主功能--- ()
----这个是主功能--- {}
---这是添加功能1----
---这是添加功能2----
----这个是主功能100---
----这个是主功能--- (200,)
----这个是主功能--- {}
---这是添加功能1----
---这是添加功能2----
----这个是主功能20---
----这个是主功能--- (50, 300)
----这个是主功能--- {'mm': '小猪猪'}
View Code

   对带有返回值的函数进行修饰:

def set_func(func):
    def call_func(num,*args,**kwargs):
        print("---这是添加功能1----")
        print("---这是添加功能2----")
        return func(num,*args,**kwargs)#  拆包
    return call_func

@set_func
def test(num,*args,**kwargs):
    print("----这个是主功能%d---" %num)
    print("----这个是主功能---" ,args)
    print("----这个是主功能---" ,kwargs)
    return "hello,python 坚持坚持坚持,加油加油加油"

ret=test(20,50,300,mm="小猪猪")
print(ret)



#####################

---这是添加功能1----
---这是添加功能2----
----这个是主功能20---
----这个是主功能--- (50, 300)
----这个是主功能--- {'mm': '小猪猪'}
hello,python 坚持坚持坚持,加油加油加油
View Code

   多个装饰器对同一个函数进行装饰:

   这时,是从最下面的一个装饰器开始装饰,然后再往上。

def set_func1(func):
    print("----开始进行添加功能1的操作")
    def call_func(*args,**kwargs):
        print("---这是添加功能(11)----")
        print("---这是添加功能(12)----")
        return func(*args,**kwargs)#  拆包
    return call_func

def set_func2(func):
    print("----开始进行添加功能2的操作")
    def call_func(*args,**kwargs):
        print("---这是添加功能(21)----")
        print("---这是添加功能(22)----")
        return func(*args,**kwargs)#  拆包
    return call_func

@set_func1
@set_func2
def test(num,*args,**kwargs):
    print("----这个是主功能%d---" %num)
    return "每天比昨天多学习一点点,就会越来越优秀,加油"

ret=test(20,50,300,mm="小猪猪")
print(ret)

##############
----开始进行添加功能2的操作
----开始进行添加功能1的操作
---这是添加功能(11)----
---这是添加功能(12)----
---这是添加功能(21)----
---这是添加功能(22)----
----这个是主功能20---
每天比昨天多学习一点点,就会越来越优秀,加油
View Code

 

 

  带有参数的装饰器:

def set_func_num(fun_num):
    def set_func(func):
        def call_func(*args,**kwargs):
            if fun_num==1:
                print("---要添加功能1----")
            elif fun_num==2:
                print("---要添加功能2----")
            return func(*args,**kwargs)#  拆包
        return call_func
    return set_func
@set_func_num(1)
def test1():
    print("----这个是主功能1---" )
@set_func_num(2)
def test2(*args,**kwargs):
    print("----这个是主功能2---" )
test1()
test2()

################
---要添加功能1----
----这个是主功能1---
---要添加功能2----
----这个是主功能2---
View Code

 

posted @ 2018-09-27 22:46  小猪猪猪  阅读(145)  评论(0)    收藏  举报