美文网首页魔术方法
python—闭包函数&装饰器

python—闭包函数&装饰器

作者: 小二哥很二 | 来源:发表于2019-10-06 13:47 被阅读0次

一、闭包的定义:

闭包函数需要满足三个条件才是闭包:

  1. 函数内部嵌套一个函数;
  2. 外层函数返回内层函数的函数名;
  3. 内层函数对外部作用域,至少有一个非全局变量的引用...
例子NO.1
def func(b):                          #参数b也是外部作用域的非全局变量
    a=100                             #a为外部作用域的非全局变量
    def wrapper():                    #嵌套函数
        print(b*200)                  #对外部函数的引用
        print(a+100)
        print('hello,这是内层函数的嵌套函数')
    return wrapper                    #返回内层函数

c=func(2)
print(c)
c()

运行结果:
>>
<function func.<locals>.wrapper at 0x0000026E640B47B8>
400
200
hello,这是内层函数的嵌套函数
>>
=================================================
例子NO.2
def func(b):
    a=100
    def wrapper():
        print('----wrapper----')
        b()                  #直接调用所传入的功能函数
        print('hello,这是内层函数的嵌套函数')
    return wrapper

def user_info():
    print('这个是显示个人信息的功能函数')

f=func(user_info)                                          #传入的参数为一个功能函数
f()

运行结果:
>>
----wrapper----
这个是显示个人信息的功能函数
hello,这是内层函数的嵌套函数
<<

判断是否是闭包函数:是闭包则返回cell,不是则返回None

def outer():
    money = 0
    def inner():
        nonlocal money
        money += 100
        print(money)
    return inner

res = outer()
res()

print(res.__closure__)
print(outer().__closure__)
===============================================
(<cell at 0x000001CBECE59138: int object at 0x00007FF92573EFB0>,)
(<cell at 0x000001CBFD6008E8: int object at 0x00007FF92573E330>,)

二、一般装饰器

闭包函数就是种装饰器

1)无参数的装饰器
例子NO.1
def func(b):
    a=100
    def wrapper():
        print('----wrapper----')
        b()
        print('hello,这是内层函数的嵌套函数')
    return wrapper

@func           #==> user_info = func(user_info)
def user_info():
    print('这个是显示个人信息的功能函数')

user_info()     # 加了装饰器func(),这里直接调用就可以

运行结果:
>>
----wrapper----
这个是显示个人信息的功能函数
hello,这是内层函数的嵌套函数
<<
=================================================
例子NO.2
#装饰器函数
def decorator(func):      #装饰器函数必须传参
    def wrapper():
        #再这里可以写装饰器扩展的新功能
        user=input('账号:')
        pwd=input('密码:')
        if user=='python' and pwd=='123':
            print('账号密码正确,调用原来的功能函数')
            func()
        else:
            print('账号密码错误~!')
    return wrapper

@decorator    #相当于调用 user_info=decorator(user_info)
def user_info():
    print('这个是显示个人信息的功能函数')

user_info()
2)内部函数有参数的装饰器
def decorator(func):
    # 如果被装饰的函数带有参数,那么内函数必须也有对应数量的的参数
    # 因为调用原函数,等于调用内函数
    def wrapper(a,b):
        print('打印两个数相减的结果',a-b)
        func(a,b)         #调用的是add_number函数,所以要传参
    return wrapper

@decorator                #==>add_number=decorator(add_number)
def add_number(a,b):
    print('两个数相加的结果',a+b)

add_number(2,3)

运行结果:
>>
打印两个数相减的结果 -1
两个数相加的结果 5
<<

如果被装饰的函数带有参数,那么内函数必须也有对应数量的的参数
因为调用原函数,等于调用内函数

3)外部函数有参数的装饰器

如果装饰器需要有参数,那么给当前的装饰器套一个壳,用于接受装饰器的参数

def insert_var(value):
    def outer(func):
        def inner1():
            print(f'参数{value}:妹子给了你微信')
            func()

        def inner2():
            print(f'参数{value}:妹子给介绍了个白富美')
            func()
        # 装饰器壳的参数,可以用于在函数内做流程控制
        if value == "白富美":
            return inner2
        else:
            return inner1
    return outer

@insert_var('白富美')
def love():
    print('淡淡人生')

love()

结果:
参数白富美:妹子给介绍了个白富美
淡淡人生

三、高阶装饰器

1)无参数的类装饰器
Python中有一个有趣的语法,只要定义类型的时候,实现__call__函数,这个类型就成为可调用的。换句话说,我们可以
把这个类型的对象当作函数来使用,相当于 重载了括号运算符。
NO.1
class logger(object):
    def __init__(self,func):
        self.func=func
    def __call__(self, *args, **kwargs):    #__call__方法接收被装饰函数,实现装饰逻辑。
        print("[INFO]:the function {func}() is running...".format(func=self.func.__name__))
        return self.func(*args,**kwargs)
@logger
def say(something):
    print('say{}!'.format(something))
say('hello')

NO.2
class Person(object):
    def __init__(self, name, gender):
      self.name = name
      self.gender = gender

    def __call__(self, friend):
      print 'My name is %s...' % self.name
      print 'My friend is %s...' % friend
  #现在可以对 Person 实例直接调用:
p=Person('Bob','Male')
p('Lily')
运行结果:
==>my name is Bob
my friend is lily

NO.3
class Outer:

    # 魔术方法:当把该类的对象当作函数调用时,自动触发obj()
    def __call__(self, func):
        self.func = func
        return self.inner

    def inner(self, who):
        print('拿到了妹子的微信')
        self.func(who)
        print('看了一场午夜电影')


@Outer()
def love(who):
    print(f'{who}和妹子谈谈人生。。。。')

love('lisa')

==>运行结果:
拿到了妹子的微信
lisa和妹子谈谈人生。。。。
看了一场午夜电影
2)三大内置装饰器之一:描述符 property
NO.1 property的只读性
class person():
    def __init__(self,name,age=18):
        self.name=name
        self.__age=18

    @property
    def age(self):
        return self.__age

xm=person('lily')   #实例化
print(xm.age)       #结果为18
xm.age=22           #报错无法给年龄赋值
print(xm.age)

==>运行结果:
    xm.age=22
AttributeError: can't set attribute
18
NO.2 用@property装饰过的函数,会将一个函数定义成一个属性,属性的值就是该函
数return的内容。同时,会将这个函数变成另外一个装饰器。就像后面我们使用的@age.setter和@age.deleter
class student():
    def __init__(self,name):
        self.name=name
        self.name=None

    @property                     
    def age(self):                 #该方法函数为student的一个属性,属性的值就是该函数
        return self._age

    @age.setter                    #age函数变成另外一个装饰器
    def age(self,value):
        if not isinstance(value,int):
            raise ValueError('输入不合法,年龄必须为整数!')
        if not 0<value<100:
            raise ValueError('输入不合法,年龄必须0~100')
        self._age=value            #给装饰器property的函数赋值,将形参传递的实参赋给函数
    @age.deleter
    def age(self):
        del self._age
xiaoming=student('小明')
xiaoming.age=11
print(xiaoming.age)
del xiaoming.age
print(xiaoming.age)

四、嵌套装饰器

def test1(f):
    def inner():
        print('成功拿到妹子的微信....3')
        f()
        print('成功约到妹子看电影....4')
    return inner

def test2(f):
    def inner():
        print('我是扩展1')
        f()
        print('我是扩展2')
    return inner


@test2
@test1
def love():
    print('跟妹子深入畅谈人生和理想。。。。。。5')


love()   # 1 3 5 4 2顺序执行,先输出最外层的装饰器结果

结果:
我是扩展1
成功拿到妹子的微信....3
跟妹子深入畅谈人生和理想。。。。。。5
成功约到妹子看电影....4
我是扩展2

五、函数装饰器给类装饰

使用函数装饰器,给类进行装饰,增加新的数据和方法

def decorate(cls):
    def func1():
        print('我是在装饰器中追加的新方法:func1')
    cls.func1 = func1   # 把刚才定义的方法赋值给类
    # 新增加的类属性
    cls.name = "我是在装饰器中追加的新属性:name"

    # 返回时,把追加类新成员的 类 返回
    return cls


@decorate
class Demo:
    def __init__(self):
        print('Demo init')


Demo()
Demo.func1()
print(Demo.name)

# 等于
# res = Demo()
# print(res.name)

输出结果:
Demo init
我是在装饰器中追加的新方法:func1
我是在装饰器中追加的新属性:name

相关文章

  • python装饰器

    装饰器简述 要理解装饰器需要知道Python高阶函数和python闭包,Python高阶函数可以接受函数作为参数,...

  • python之理解闭包和装饰器

    python之理解闭包和装饰器 1、闭包函数 1.1 python中函数都是对象 结果: 上面定义一个shut函数...

  • Python装饰器-专题笔记

    学会装饰器,Python更进阶 函数作用域到闭包到装饰器讲解,及闭包和装饰器的运用。 [√] 慕课网Meshare...

  • Python 2 - 高级用法 - 装饰器

    Python 2 - 高级用法 - 装饰器 一谈到 装饰器,就离不开闭包 闭包 闭包就是能够读取其他函数内部变量的...

  • Python 装饰器的诞生过程

    Python中的装饰器是通过利用了函数特性的闭包实现的,所以在讲装饰器之前,我们需要先了解函数特性,以及闭包是怎么...

  • 只需四步,让你了解Python装饰器的诞生过程

    Python中的装饰器是通过利用了函数特性的闭包实现的,所以在讲装饰器之前,我们需要先了解函数特性,以及闭包是怎么...

  • python中的函数

    关于python中的值传递和址传递 匿名函数 缺省函数 闭包 装饰器

  • 2020-012 python闭包与装饰器

    python闭包与装饰器 闭包 函数和对其周围状态(lexical environment,词法环境)的引用捆绑在...

  • chapter7 函数式编程

    闭包 匿名函数 装饰器 偏函数

  • Python装饰器与闭包!

    闭包是Python装饰器的基础。要理解闭包,先要了解Python中的变量作用域规则。 变量作用域规则 首先,在函数...

网友评论

    本文标题:python—闭包函数&装饰器

    本文链接:https://www.haomeiwen.com/subject/atrupctx.html