zoukankan      html  css  js  c++  java
  • 函数高级:装饰器

    print('装饰器知识总结与练习'.center(50,"#"))
    '''
    一,函数对象
    要理解装饰器,首先要理解函数对象的概念,简单的说,当我们定义了一个函数,
    def func():
    pass
    调用的时候,直接func() 后面加括号就表示调用函数并且运行
    这里的func 这个变量名,绑定的就是函数函数程序块的一个地址,
    这个变量名,就是我们的函数对象
    函数对象后面加括号,表示函数的调用
    这个函数对象还可以再赋值给其他变量,例如:
    f1 = func 把func这个函数对象赋值给f1,绑定在一起,
    现在执行原来的函数 也可以通过f1加括号实现,也就是
    f1() = func() 这两个的效果是一样的
    二 名称空间
    什么是名称空间?名称空间:存放变量名字的地方
    名称空间的加载顺序
    #1、python解释器先启动,因而首先加载的是:内置名称空间
    #2、执行test.py文件,然后以文件为基础,加载全局名称空间
    #3、在执行文件的过程中如果调用函数,则临时产生局部名称空间

    三 作用域
    #1、作用域即范围
    - 全局范围(内置名称空间与全局名称空间属于该范围):全局存活,全局有效
      - 局部范围(局部名称空间属于该范围):临时存活,局部有效
    #2、作用域关系是在函数定义阶段就已经固定的,与函数的调用位置无关,如下
    #3、查看作用域:globals(),locals()

    LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__
    locals 是函数内的名字空间,包括局部变量和形参
    enclosing 外部嵌套函数的名字空间(闭包中常见)
    globals 全局变量,函数定义所在模块的名字空间
    builtins 内置模块的名字空间
    总结:在一个有着嵌套函数的最内部函数中,查找一个变量,首先在当前函数的局部名称空间中查找,查找不到
    的话就在外面一层函数的名称空间中查找,找不到就再往外找,一直往外找,最后找全局的,找内置的,实在找不到
    就报错,也就是说从内向外找,不能向里面查找.


    四:闭包与闭包函数
    要理解装饰器,首先要理解闭包与闭包函数,装饰器其实就是闭包函数的一种应用
    我们首先来看闭包
    一 什么是闭包?
    #内部函数中有对外部作用域外部的变量而非全局作用域的引用,也就是内层的东西用到了外层的变量参数
    外层函数将内层函数包裹起来,并且给内层函数传递参数,这种结构叫做闭包
    #提示:之前我们都是通过参数将外部的值传给函数,闭包提供了另外一种思路,
    包起来喽,包起呦,包起来哇
    def counter():
    n=0
    def incr():
    print(n)
    return incr
    counter() ####这条语句不会打印任何内容,
    counter()() ####这条语句会打印出n的值出来
    # counter() = incr
    # counter()()= incr()
    二 ,闭包的意义与应用
    #闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,
    优先使用自己外层包裹的作用域
    #应用领域:延迟计算(原来我们是传参,现在我们是包起来)

    好了,铺垫了那么多的知识点,我们现在正式开始我们的装饰器的学习
    五,装饰器:
    装饰器就是闭包函数的一种应用场景
    1,为何要用装饰器
    为了实现与满足开放封闭原则:对修改封闭,对扩展开放

    2, 什么是装饰器
    装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
    强调装饰器的原则:
    1 不修改被装饰对象的源代码
    2 不修改被装饰对象的调用方式
    装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能

    3,实例:装饰器的使用


    '''

    #####应用场景:现在又这个一个foo的函数,要求为这个函数增加新的功能,计算这个函数的运行时间并输出,
    ###原来的函数
    # import time
    #
    # def foo():
    # time.sleep(2)
    # print('from foo')
    # ###如果我们直接修改这个函数的源码,可以这样做
    #
    # def foo1():
    # start_time = time.time()
    # ##获取函数开始执行的时间
    # time.sleep(2)
    # print('from foo')
    # ###原来函数的代码
    # end_time = time.time()
    # ###获取函数结束的时间
    # print(end_time - start_time)

    # foo1()

    # foo()
    ###这种做法实现了这种功能,达到了我们的需求,但是我们修改了函数调用的方式,
    ####之前我们都是用foo调用这个函数,现在我们是用foo1调用这个函数,
    ###修改了函数的调用方式,如果这个函数在其他地方经常被调用的话,那么我们就需要在
    # 所有的程序中全部修改这个调用方式,这样不太好,
    ##如果我们采用赋值foo = foo1 这样可以不改变调用方式,但是原来的foo绑定的函数块也就
    ##没有任何东西绑定了,也就会被回收,只剩下了foo1,那么这也就相当于改变了源代码,
    # 这种做法也不可取
    ##接下来我们看看如何用装饰器完美的解决这个问题
    ##运用装饰器的做法:

    # import time
    # def timmer(func):
    # def wrapper(*args,**kwargs):
    # start_time=time.time()
    # ####在这个位置原来函数执行之前可以添加装饰代码
    # res=func(*args,**kwargs)
    # ####在这个位置原来函数执行之后也可以添加装饰代码
    # stop_time=time.time()
    # print(stop_time-start_time)
    # return res
    # return wrapper
    # @timmer ###这个语法叫做语法糖,在这里等价于 foo = timmer(foo)
    # def foo():
    # time.sleep(2)
    # print('from foo')
    # foo()
    '''
    上面的实例是没有参数的装饰器,下面来演示一个有参数的装饰器
    需求:
    原来的函数:这个函数就只有一个小功能,就是接收到输入的名字,并且打印
    他是世界上最牛的程序员

    def foo(name):
    print('%s是这个世界上牛的程序员' %name)

    现在要给这个函数添加一个登录认证的功能,在使用这个功能之前,要先登录


    def auth(func):
    def inner(*args,**kwargs):
    while True:
    name = input('请输入您的账号===>').strip()
    pwd = input('请输入您的密码===>').strip()
    if name == 'szp' and pwd == '123':
    print('登录成功')
    res = func(*args,**kwargs)
    return res
    else:
    print('账号或者密码不正确,请重新输入')
    return inner


    @auth
    def foo(name):
    print('%s是这个世界上牛的程序员' % name)

    foo('萧十一郎')

    更加复杂的装饰器应用:

    def auth(driver='file'):
    def auth2(func):
    def wrapper(*args,**kwargs):
    name=input("user: ")
    pwd=input("pwd: ")

    if driver == 'file':
    if name == 'egon' and pwd == '123':
    print('login successful')
    res=func(*args,**kwargs)
    return res
    elif driver == 'ldap':
    print('ldap')
    return wrapper
    return auth2

    @auth(driver='file')
    def foo(name):
    print(name)

    foo('egon')
    '''
    '''

    '''
    #一:编写函数,(函数执行的时间是随机的)
    # import time
    # import random
    # def func():
    # delay_time_num = random.randint(1, 3)
    # time.sleep(delay_time_num)
    # print('hello world')
    # print('函数延迟了%s秒才执行' % delay_time_num)
    #
    # func()

    ##z在上一题的基础上为函数编写装饰器,统计函数的执行时间
    # import time
    # import random
    #
    # def time_counter(func):
    # def inner(*args,**kwargs):
    # start_time = time.time()
    # res = func(*args,**kwargs)
    # end_time = time.time()
    # print('函数的执行时间是%s秒'%(end_time - start_time))
    # return res
    # return inner
    # @time_counter
    # def func():
    # delay_time_num = random.randint(1, 3)
    # time.sleep(delay_time_num)
    # print('hello world')
    # print('函数延迟了%s秒才执行' % delay_time_num)
    #
    # func()


    #三:编写装饰器,为函数加上登录认证的功能
    from interface import user_interface

    user_login = {'name':None,'pwd':'','money':0}
    ##登录
    def denglu():
    print('登录功能'.center(50,"*"))
    with open(r'D:ATMusr_info', 'r', encoding='utf-8') as f:
    date = f.read()
    # print(date)
    user_name, user_pwd, user_money = date.split('|')
    while True:
    name = input('请输入您的账号').strip()
    if name != user_name:
    continue
    pwd = input('请输入您的密码').strip()
    if pwd != '123':
    continue
    user_login['name'] = name
    user_login['pwd'] = pwd
    user_login['money'] = 100#######默认账户余额设置为100
    print('登录成功')
    break



    # user_login2 = {'name': 'szp', 'pwd': '123', 'money': 100}

    ###查看账户余额
    def check_balance(name):
    print(user_login['money'])


    denglu()
    check_balance()
  • 相关阅读:
    20121010 闲的慌的日子
    九月,桂花飘香的季节
    win7下控件(ActiveX)注册错误(0x80040200) 修正
    C#多线程技术(一)
    C#多线程技术(二)
    C++沉思录摘录(OOP部分)
    SVM入门教程
    是IE的bug还是Windows的bug?
    inno setup安装时不需要开始菜单项
    django本地局域网访问
  • 原文地址:https://www.cnblogs.com/1832921tongjieducn/p/10875036.html
Copyright © 2011-2022 走看看