• python进阶(三)~~~装饰器和闭包


    一、闭包

      满足条件:

      1. 函数内嵌套一个函数;

      2.外层函数的返回值是内层函数的函数名;

      3.内层嵌套函数对外部作用域有一个非全局变量的引用;

    def func():
        print("===func====")
        num=2
        def wrapper():
            print("------wrapper------")
            print(num2)   # 或者直接引用func的传参
        return wrapper
    
    res=fun()
    res()

       闭包的作用:实现数据锁定,不受外部影响。

    二、装饰器

      开放封闭原则:面向对象的核心。软件实体应当是可扩展,而不可修改的。也就是说,对扩展是开放的,对修改是封闭的。

      装饰器:在不改变原来函数功能的情况下,进行扩展。同时,不改变调用方式。

      使用:@装饰器名称。 @为装饰器的语法糖

      常见应用场景

        1. 权限校验,预判断是否有执行函数功能的权限;

        2. 计时,计算函数运行时间;

        3. 进行环境准备和恢复工作;

        4. web自动化用例失败截图;

    #  示例4:失败截图装饰器
    from selenium import webdriver
    
    browser=webdriver.Chrome()
    browser.get("https://www.baidu.com")
    
    def decorator(func):
        def wrapper():
            try:
                func()
            except:
                browser.save_screenshots("error.png")
                raise e
         return wrapper
    
    @decorator
    def test_search():
        browser.find_element_by_xpath("//input[@id='kw']").sendkeys("ninmen")
        browser.find_element_by_xpath("//input[@id='su123']").click()
    
    test_search()        

      1、普通装饰器

    def decorator(func):
        def wrapper():
            print("----这是装饰器内层函数----")
            func()
        return wrapper
    
    @decorator  # 等同于执行func = decorator(func)
    def func():
        print("====这是原功能函数====")
    
    func()  # 此时,不改变调用方式的同时,实现了功能扩展

      2、带参数的装饰器

      3、通用装饰器

    #带参数
    def decorator(func):
        def wrapper(a,b):
            print("----这是装饰器内层函数----")
            func(a,b)
        return wrapper
    
    #通用
    def decorator(func):
        def wrapper(*args,**kwargs):
            print("----这是装饰器内层函数----")
            func(*args,**kwargs)
        return wrapper
    
    @decorator  # 等同于执行func = decorator(func)
    def func(a,b):
        print("====求和====",a+b)
    
    func() 

      4、类实现装饰器

      __call__:魔术方法,在对象使用括号时被触发,如果在类中实现了 __call__ 方法,那么实例对象也将成为一个可调用对象

      平时自定义的函数、内置函数和类都属于可调用对象,但凡是可以把一对括号()应用到某个对象身上都可称之为可调用对象,判断对象是否为可调用对象可以用函数 callable

    class Decorator():
        '''类实现通用的装饰器'''
        def __init__(self,func):
            self.func=func
    
        def __call__(self,*args,**kwargs):
            print("----这是装饰器内层函数----")
            return self.func(*args,**kwargs)
    
    @Decorator  # 等同于执行func = Decorator(func),将func转换成Decorator类的一个对象
    def func(a,b):
        print("====求和====",a+b)

      5、装饰器装饰类

    class Decorator():
        '''类实现通用的装饰器'''
        def __init__(self,func):
            self.func=func
    
        def __call__(self,*args,**kwargs):
            print("----这是装饰器内层函数----")
            return self.func(*args,**kwargs)
    
    @Decorator  # 等同于执行func = Decorator(Hero)
    class Hero:
        def func(a,b):
            print("====求和====",a+b)
    
    h=Hero()
    h.func()
    
    #也可以使用 2中的通用装饰器
    def decorator(func):
        def wrapper(*args,**kwargs):
            print("扩展功能")
            obj=func(*args,**kwargs)   
             return obj   #返回类对象
        return wrapper
    
    @decorator  # 等同于执行func = decorator(Hero)
    class Hero:
        def func(a,b):
            print("====求和====",a+b)
    
    h=Hero()
    h.func()

      6、三个内置的装饰器

      1、@property 将某函数,做为属性使用

      property可以将python定义的函数当做属性访问,从而提供更加友好访问方式,但是有时候setter/deleter也是需要的

      只有@property表示只读。
      同时有@property和@x.setter表示可读可写。
      同时有@property和@x.setter和@x.deleter表示可读可写可删除。

    class Foo:
        def __init__(self, name):
            self.__name = name
    @property
    def name(self): return self.__name
    @name.setter def name(self, value): if not isinstance(value, str): raise TypeError('name must be str') self.__name = value
    @name.deleter
    def name(self): raise TypeError('can not delete')
    f
    = Foo('jack') print(f.name) # jack f.name = 'hanmeimei' print(f.name) # hanmeimei # del f.name # TypeError: can not delete

      2、@classmethod 修饰类的方式:仅仅与类交互而不和实例交互,类在使用时会将类本身当做参数传给类方法的第一个参数

      带修饰类方法:cls做为方法的第一个参数,隐式的将类做为对象,传递给方法,调用时无须实例化。

      普通函数方法:self做为第一个参数,隐式的将类实例传递给方法,调用方法时,类必须实例化。

    class Date:
    
        def __init__(self, year, month, day):
            self.year = year
            self.month = month
            self.day = day
    
        @classmethod
        def now(cls):
            t = time.localtime()
            return cls(t.tm_year, t.tm_mon, t.tm_mday)
    
        def __str__(self):
            return '%s-%s-%s' % (self.year, self.month, self.day)
    
    e = Date.now()
    print(e)  # 2018-8-1

      3、@staticmethod 修饰类的方式

      1) 静态方法和在普通的非class的method作用是一样的,只不过是命名空间是在类里面。

      2) 一般使用场景就是和类相关的操作,但是又不会依赖和改变类、实例的状态,比如一些工具方法。

    class Date:
    
        def __init__(self, year, month, day):
            self.year = year
            self.month = month
            self.day = day
    
        @staticmethod
        def now():
            t = time.localtime()
            return Date(t.tm_year, t.tm_mon, t.tm_mday)
    
        def __str__(self):
            return '%s-%s-%s' % (self.year, self.month, self.day)
    
    e = Date.now()
    print(e)  # 2018-8-1
  • 相关阅读:
    spring 注解学习 一 Bean的注入
    jdk动态代理详解 二 代理失效
    jdk动态代理详解 一 入门
    tomcat中web应用的目录结构
    mongoose与mongodb 的版本兼容性表格
    树莓派3B安装ffmpeg过程记录
    ESP8266驱动SSD1306 ESP8266 for Arduino(NodeMCU U8G2库)
    ESP8266 for Arduino开发环境安装
    Mongodb3.4升张到4.0过程
    使用webgl(three.js)创建自动化抽象化3D机房,3D机房模块详细介绍(抽象版一)
  • 原文地址:https://www.cnblogs.com/qingyuu/p/12255564.html
Copyright © 2020-2023  润新知