美文网首页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