闭包 偏函数和数据锁定

一,闭包条件

1,函数中嵌套函数

2,外层函数返回内层嵌套函数名

3,内层嵌套函数有引用外层的一个非全局变量,内部嵌套函数不能引用全局变量

二,作用

实现数据的锁定,提高稳定性 通过

index = login(index) 

index.__closure__可以查看对外层非全局变量的引用

三,装饰器的实现

 开放封闭原则:软件应该是可扩展的,而不可修改

def index():

  pass

需求:需要对index加校验功能,但由于开放封闭原则,因此不能直接修改index函数

# 外层函数参数是被装饰的函数

def login(index):

  def func():

    # 校验功能

    pass

    # 放入被装饰的函数

    index()

  # 外层函数返回值是内层函数

  return func

执行:

#@login 语法糖 index = login(index)  

# index .__closure__ 这里面存储了内部函数调用外部函数的变量,也就是index函数

@login 

def index():

  pass

四,装饰器的作用

在不更改原功能函数内部代码,并且不改变调用方法的情况下为原函数添加新功能。

五,装饰器的应用场景

1,登录验证

2,函数运行时间统计

3,执行函数之前做准备

4,执行函数后清理工作

六,通用装饰器

如果同一个装饰器既要装饰有参数的函数,又要装饰无参数的函数,那么我们在传参的时候就设置成不定长参数,这样不管被装饰的函数有没有参数都能用

def f1(func):
    def fun(*args, **kwargs):
        print('执行装饰器中的函数')
        func(*args, **kwargs)
    return fun

@f1
def func(a, b):
    print('执行函数--func')
    print(a + b)

func(10, 20)

七,类装饰器

前面是用闭包函数实现的装饰器,也可以使用类当作一个装饰器。

把类当作装饰器有两步操作:

1,首先在__init__方法中,把装饰器函数赋值给一个实例属性

2,然后在类里面实现一个__call__方法,在call方法中调用原来的函数

def add(func):

  def fun(*args, **kwargs):

    print('装饰器的功能代码:登录')
    return func(*args, **kwargs)
  return fun

# myClass = login(MyClass)

@login

class MyClass:

  def __init__(self):

    pass

八,装饰器装饰类 

注意:装饰器装饰类fun中的return必须要写,因为类需要把对象返回出来,装饰函数的话return不一定要写

def add(func):

    def fun(*args, **kwargs):
        print('装饰器的功能代码,登录验证')
        return func(*args, **kwargs)
    return fun

@add             # MyClass = add(MyClass)----返回fun
class MyClass:
    def __init__(self, name, age):
        self.name = name
        self.age = age

# 相当于fun('小鱼', 18),fun函数中如果没有return 那么该函数默认返回None,装饰之后该类不能创建对象了
m = MyClass('小鱼', 18)
print(m)

九,多个装饰器装饰同一个函数

从下往上装饰,装饰顺序:@decorator -> @login_check

从上往下执行,执行顺序:@login_check -> @decorator -> login()函数


import time
def decorator(func):
def count_time(*args, **kwargs):
print('进入计算时间的装饰器')
start_time = time.time()
func()
end_time = time.time()
spend_time = end_time - start_time
print('函数运行的时间为:',spend_time)
return count_time

with open(file='d:login.txt', mode='r+', encoding='utf-8') as f:
data = eval(f.read())

def login_check(func):

def ado(*args, **kwargs):
print('进入登录校验装饰器函数')
if data.get('token') is not True:
print(data.get('token'))
n = input('请输入名字:')
p = input('请输入密码:')

if data.get('name') == n and data.get('passwd') == p:
data['token'] = True
func(*args, **kwargs)
else:
print('输入错误')
else:
func(*args, **kwargs)
return ado

@login_check #login = login_check(login) login指向ado函数
@decorator # login = decorator(login) login指向count_time函数
def login():
time.sleep(3)
print('这是需要被装饰的函数')

login()

十,类中三个装饰器

类方法:类 实例对象都可以调用

实例方法:类不能调用 实例可以调用

静态方法:类 实例对象都可以调用

class MyTest():
  def __init__(self,name):
    self.name = name @classmethod
# 被classmethod装饰后,该方法是个类方法 def add(cls): # cls代表类本身 print('add') print(cls) def sub(self): # self代表实例本身 print(self)

  @staticmethod   
  def static():   # 静态方法是没有参数的
    pass
  
  @property
  def read_attr(self):  # 设置只读属性,防止被串改,可以像属性一样调用,注意,这里的属性不能修改,init中的属性可以被修改
    return '18' t
= MyTest() t.add() # 类属性 类方法可以被实例调用 t.sub() #
t.static()     # 静态方法可以被类调用
t.read_attr    # t.read_attr()错误
MyTest.add() # MyTest.sub() # 错误,实例方法不能被类调用
MyTest.static() #静态方法可以被类调用
原文地址:https://www.cnblogs.com/ella-li/p/13946070.html