美文网首页Python散文想法
python 代理模式和装饰器总结

python 代理模式和装饰器总结

作者: Cache_wood | 来源:发表于2021-11-14 23:53 被阅读0次

    @[toc]

    代理模式

    proxy pattern
    • 在访问某个对象之前执行一个或多个重要的额外操作
    • 访问敏感信息或关键功能需要具备足够的权限
    • 将计算成本较高的对象创建过程延迟到用户首次真正使用时才进行
    常见类型
    • 远程代理:实际存在于不同地址空间的对象在本地的代理者
    • 虚拟代理:用于惰性求值,将一个大计算量对象的创建延迟到真正需要的时候进行
    • 保护/防护代理:控制对敏感对象的访问
    • 智能(引用)代理:在对象被访问时执行额外的动作,如计算计数或线程安全检查等

    装饰器

    函数式编程
    • 面向对象,但更接近于数学计算
    • 一种抽象程度更高的编程范式
    • 允许将函数作为参数传入另一个函数
    • 允许返回另一个函数
    • python支持部分的函数式编程
    高阶函数
    • 接受另一个函数作为参数的函数
    list(map(f,[x1, x2, x3, x4]))=[f(x1),f(x2),f(x3),f(x4)]
    reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
    list(filter(f,[x1,x2,x3,x4]))=[x for x in [x1,x2,x3,x4] if f(x)]
    

    举例

    返回函数
    ##惰性函数
    def lazy_sum(*args):
        def sum():
            ax = 0
            for n in args:
                ax = ax + n
            return ax
        return sum
    f = lazy_sum(1, 3, 5, 7, 9)
    print(f)
    print(f())
    
    <function lazy_sum.<locals>.sum at 0x000001D4B49CDEE0>
    25
    

    对惰性函数的理解:因为惰性函数自身嵌套了子函数,所以在调用惰性函数时,实际上是调用了子函数,子函数的结果返回但不会输出。 这样在不必要的时候我们可以避免输出。

    偏函数

    为简化多参数函数的调用,可通过固定某参数来返回新函数,以实现简化调用。

    import functools
    
    def growth(step=1,limit=200):
        g=0
        while(True):
            if g+step>limit:
                break
            g += step
        return g
    print(growth())
    print(growth(step=3))
    growth3=functools.partial(growth,step=3)
    print(growth3())
    print(growth3(limit=300))
    
    200
    198
    198
    300
    
    闭包

    返回函数不宜引用任何循环变量,或者后续会发生变化的变量

    def count():
        fs = []
        for i in range(1, 4):
            def f():
                return i
            fs.append(f)
            print(fs)
        return fs
    f1, f2, f3 = count()
    print(f1())
    print(f2())
    print(f3())
    #每次存储的是子函数本身,并没有调用,结果相同
    3
    3
    3
    
    def count():
        def f(j):
            def g():
                return j
            return g
        fs = []
        for i in range(1, 4):
            fs.append(f(i)) 
        return fs
    f1,f2,f3=count()
    print(f1())
    print(f2())
    print(f3())
    #增加一层子函数,每次存储最内层函数的调用实例,f(i)立刻被执行,所以返回每次不同的结果
    1
    2
    3
    
    装饰器

    在不修改原始代码的前提下增强或扩展既有功能

    • 在核心功能的基础上增加额外的功能,如授权(Authorization)、日志(Logging)
    def log(func):
        def wrapper(*args,**kwargs):
            print("call " + func.__name__)#额外的功能
            return func(*args,**kwargs) #调用原功能
        return wrapper
    @log #使用装饰器
    def now():
        pass
    now()  #相当于log(now)()
    
    call now
    

    通过装饰器后函数名称发生了变化
    保持不变化,需要

    functools.wraps(func)
    

    @wraps复制了函数名称、注释文档、参数列表等,使得能够在装饰器里访问在装饰之前的函数属性

    在实现装饰器时应在wrapper函数前加入@wraps,避免因函数内部功能逻辑对函数属性的依赖而导致功能错误

    装饰器类
    from functools import wraps
    
    class Log:
        def __init__(self,logfile='out.log'):
            self.logfile=logfile
    
        def __call__(self,func):
            @wraps(func)
            def wrapper(*args,**kwargs):
                info="INFO: "+func.__name__+" was called"
                with open(self.logfile,'a') as file:
                    file.write(info+'\n')
                return func(*args,**kwargs)
            return wrapper
    @Log('test.log')#@Log()
    def myfunc():
        pass
    myfunc()#相当于Log('test.log')(myfunc)()
    
    INFO: myfunc was called
    
    装饰器的顺序
    • 装饰顺序:就近原则(从下往上装饰)
    • 调用顺序:就远原则(从上往下调用)
    property

    使实例方法的调用如同实例属性

    @property #读取属性
    @方法名.setter #修改属性
    @方法名.deleter #删除属性
    

    也可通过property()方法获取,设置,删除,描述文档

    id = property(get_id, set_id, del_id, 'id is ……')
    
    类方法与静态方法
    • 实例方法需要通过self参数隐式的传递当前类对象的实例
    • 用@classmethod修饰的方法需要通过cls参数传递当前类对象,称为类方法
    • 用@ststicmethod修饰的方法定义与普通函数一样,称为静态方法
    • 类方法和静态方法均可通过类对象或实例对象调用

    相关文章

      网友评论

        本文标题:python 代理模式和装饰器总结

        本文链接:https://www.haomeiwen.com/subject/roowzltx.html