闭包和装饰器

一、python闭包

1、生命周期

def outer():
    a = 10
    print(f"test {a}")
outer()

2、闭包要满足的条件

2.1、必须要有内嵌函数
​	2.2、内涵数必须要引用外函数的变量
​	2.3、外函数必须返回内函数
	示例:
		def outer(x):
		    a = 300
		    def inner():
		        print(x+a)
		    return inner
		d = outer(100)
		d()
		print(dir(d))
		#形成闭包之后,闭包函数就会得到一个非空的__closure__属性
		print(outer.__closure__,d.__closure__)

3、用闭包实例化的对象
.虽然代码都一样,但是创建的对象是不一样的,每次调用外函数都会重新执行,创建一个新的tmp_list和inner

def outer():
    tmp_list = []
    def inner(name):
        tmp_list.append(name)
        print(tmp_list)
    return inner
d1 = outer()
d1("d1")
d1('d1')
d2 = outer()
d2('d2')
d2("d2")
二、装饰器

1、装饰器的介绍

1.是一种程序设计模式,不改变函数或类的源代码基础上,添加额外功能
2.装饰器的本质就是闭包函数,它需要把一个callable(函数,类)对象作为参数传递进来

2、引出装饰器

#为了引出装饰器
import time
#时间戳:
	从1970到现在所经历的秒数
def func1():
    time.sleep(2)
    print("func1.........")

def func2():
    time.sleep(3)
    print("func2.........")
start = time.time()
func1()
end = time.time()
print(f"func1执行花了{end - start }秒")

start = time.time()
func2()
end = time.time()
print(f"func2执行花了{end - start }秒")

3、统计运行时间的装饰器

#除了主功能之外还实现了其他功能
import time
def runtime(func):
    def inner(*args,**kwargs):
        start = time.time()
        result = func(*args,**kwargs)	#让装饰器更加通用
        end = time.time()
        print(f"执行函数花了{end - start}秒")
        return result
    return inner
# @ 修饰符,去使用装饰器
@runtime    #func1 = runtime(func1)
def func1():
    time.sleep(2)
    print("func1.........")
    return "sanchuang"
@runtime
def func2(a,b):
    time.sleep(3)
    print("func2.........")
    print(f"fun2...{a}{b}")

result = func1()
print(result)
func2(1,2)

4、用装饰器实现权限控制

import functools
import time
def deco(name):
    def runtime(func):
        #保留传递进来的函数的原数据,将它的原数据赋值给inner
        @functools.wraps(func)
        def inner(*args,**kwargs):
            if name=="root":
                print("欢迎")
                print(f"func name is {func.__name__}")
                result = func(*args,**kwargs)
                return result
            else:
                return "没有权限"
        return inner
    return runtime

username = input("请输入你的用户名:")
@deco(name=username)
def add(a,b):
    time.sleep(3)
    return a+b
print(add(1,2))
三、装饰器的应用

1、可以应用多个装饰器去装饰函数,但是要注意装饰器的执行顺序
2、添加额外功能:计时、权限控制、日志记录等
3、案例:

import functools
import time
def runtime(func):
    #保留传递进来的函数的原数据,将它的原数据赋值给inner
    @functools.wraps(func)
    def inner(*args,**kwargs):
        start = time.time()
        result = func(*args,**kwargs)
        end = time.time()
        print(f"函数执行花了{end - start}s")
        return result
    return inner

def login_required(func):
    username = input("请输入你的用户名:")
    def inner(*args,**kwargs):
        if username=='root':
            print(f"欢迎执行{func.__name__}函数")
            result = func(*args,**kwargs)
            return result
        else:
            return "没有权限"
    return inner

@login_required
@runtime
def add(a,b):
    time.sleep(2)
    return a+b
result = add(1,2)
print(result)

@login_required
@runtime
def add2(a,b):
    time.sleep(3)
    return a+b
result1 = add2(1,2)
print(result1)
四、带参数的装饰器

1、自身不传入参数的装饰器,使用两层函数定义
2、自身传入参数的装饰器,使用三层函数定义

import functools
import time
def deco(name):
    def runtime(func):
        #保留传递进来的函数的原数据,将它的原数据赋值给inner
        @functools.wraps(func)
        def inner(*args,**kwargs):
            start = time.time()
            result = func(*args,**kwargs)
            end = time.time()
            print(f"函数执行花了{end - start}s")
            print(f"name is {name}")
            return result
        return inner
    return runtime

# runtime = deco(name = "sanle")
# func1 = runtime(func1)
@deco(name="sanle")
def func1():
    time.sleep(3)
    print("this is func1")
func1()

3、练习

	​装饰器带参数,来验证用户是否有权限运行函数
	运行add函数,运行前要判断有没有权限
​	判断一:用户名和密码是否正确			---用户名错误或密码错误
​	判断二:用户名是否为root,只有root用户有权限   		----输出用户没有权限
​	用户名和密码 通过带参传入
import functools
import time
def deco(name):
    def runtime(func):
        #保留传递进来的函数的原数据,将它的原数据赋值给inner
        @functools.wraps(func)
        def inner(*args,**kwargs):
            if name=="root":
                print("欢迎")
                print(f"func name is {func.__name__}")
                result = func(*args,**kwargs)
                return result
            else:
                return "没有权限"
        return inner
    return runtime

username = input("请输入你的用户名:")
@deco(name=username)
def add(a,b):
    time.sleep(3)
    return a+b
print(add(1,2))
五、属性包装 装饰器----property

property:把方法当作属性来使用

class Person():
    _age = 2
    @property   #property本身会创建另外两个装饰器,@age.setter  @age.deleter
    def age(self):
        return self._age
    @age.setter
    def age(self,num):
        if 0< num <120:
            self._age = num
        else:
            raise  ValueError("年龄不在范围")
p = Person()
print(p.age)
p.age = 110
print(p.age)
六、用类去实现装饰器

1、不带参数的装饰器用类实现

import time
class runtime:
    def __init__(self,func):
        self.func = func
    def __call__(self,*args,**kwargs):
        start = time.time()
        result = self.func(*args,**kwargs)
        end = time.time()
        print(f"运行函数{self.func.__name__}花费了{end - start}秒")
        return result

@runtime
def func1(a,b):
    print("this is func1......")
    time.sleep(2)
    return a+b
print(func1(1,2))

2、带参数的装饰器用类实现

import time
class runtime:
    def __init__(self,name):
        self.name = name
    def __call__(self,func):
        def deco(*args,**kwargs):
            start = time.time()
            result = func(*args,**kwargs)
            end = time.time()
            print(f"运行函数{func.__name__}花费了{end - start}秒")
            return result
        return deco

@runtime("name")
# a1 = runtime("name")
# func1 = a1(func1)
def func1():
    time.sleep(2)
    print("this is func1......")

func1()
七、装饰类
def outer(cls):
    def inner(*args,**kwargs):
        print(f"class name is:{cls.__name__}")
        return cls(*args,**kwargs)
    return inner

@outer  # A = outer(A)
class A:
    def __init__(self,name):
        self.name = name
print(type(A))
m = A("sc")
print(m.name)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值