• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
ellaha
博客园    首页    新随笔    联系   管理    订阅  订阅
闭包 偏函数和数据锁定

一,闭包条件

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() #静态方法可以被类调用
posted on 2020-11-08 21:56  ellaha  阅读(168)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3