Python的装饰器和with语法

<python 2.7>
本文分两部分,第一部分是装饰器,第二部分是with语法,
@with_connection
def do_some_db_operation():
    db.select('...')
    db.update('...')
    db.update('...')
with db.connection():
    db.select('...')
    db.update('...')
    db.update('...')

上下两个代码片的作用是一样的,关于数据库操作的,都使用了with语法,只不过上边的使用了装饰器,更加方便了。

<装饰器>

动态增加代码功能,定义一个who的装饰器:

import functools

def who(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        增加的功能'x'代码,比如 print '<我是小菜>'
        return func(*args, **kw)
    return wrapper

使用时:

@who
def beatDoudou():
    print '打豆豆'

结果:

<我是小菜>
打豆豆

关于@functools.wraps(fund)的作用是:
因为在原函数外加了一层wrapper,所以调用beatDoudou.__name__时,返回的是wrapper,并不是beatDoudou,避免有些依赖函数签名的代码执行出错。
带参数的装饰器

import functools

def who(name):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print '<我是%s>' % name
            return func(*args, **kw)
        return wrapper
    return decorator

使用时:

@who
def beatDoudou('大鸟'):
    print '打豆豆'

结果:

<我是大鸟>
打豆豆

<with 语法>
---------

使用with语法,首先要有上下文管理器(class),这个上下文管理器遵守上下文管理协议,即实现了__enter__() 和 __exit__() 方法,比如(代码看看格式就好):

class _ConnectionCtx(object):
    """
    with connection():
        pass
        with connection():
            pass
    """
    def __enter__(self):
        """
        获得一个惰性连接对象
        """
        global _db_ctx
        self.should_cleanup = False
        if not _db_ctx.is_init():
            _db_ctx.init()
            self.should_cleanup = True
        return self
    def __exit__(self, exctype, excvalue, traceback):
        """
        释放连接对象
        """
        global _db_ctx
        if self.should_cleanup:
            _db_ctx.cleanup()
#with _ConnectionCtx():关键句
def with_connection(func):
    """
    设计一个装饰器,替换with语法,让代码更优雅
    比如:
        @with_connection
        def foo(*args, **kw):
            f1()
            f2()
            f3()
    """
    @functools.wraps(func)
    def _wrapper(*args, **kw):
        with _ConnectionCtx():
            return func(*args, **kw)
    return _wrapper

with语法作用

with db.connection():
    db.select('...')
    db.update('...')
    db.update('...')

三个数据库操作成为语句块,在执行之前,先执行上下文管理器的enter函数,即获得数据库连接;在执行完语句块之后,再执行exit函数,即释放数据库连接。

with语句执行过程类似如下:

以下代码来自[这里](https://www.ibm.com/developerworks/cn/opensource/os-cn-pythonwith/)
context_manager = context_expression
    exit = type(context_manager).__exit__  
    value = type(context_manager).__enter__(context_manager)
    exc = True   # True 表示正常执行,即便有异常也忽略;False 表示重新抛出异常,需要对异常进行处理
    try:
        try:
            target = value  # 如果使用了 as 子句
            with-body     # 执行 with-body
        except:
            # 执行过程中有异常发生
            exc = False
            # 如果 __exit__ 返回 True,则异常被忽略;如果返回 False,则重新抛出异常
            # 由外层代码对异常进行处理
            if not exit(context_manager, *sys.exc_info()):
                raise
    finally:
        # 正常退出,或者通过 statement-body 中的 break/continue/return 语句退出
        # 或者忽略异常退出
        if exc:
            exit(context_manager, None, None, None) 
        # 缺省返回 None,None 在布尔上下文中看做是 False

ps:markdown编辑器有bug吧,有些内容显示不出来,只好改成代码片才可以,所以排版有点乱,sorry

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python装饰是一种高级语法,用于修改、包装或扩展函数或类的行为。装饰本身是一个函数,可以接受一个函数或类作为参数,并返回一个新的函数或类。下面是几种装饰的使用方式: 1. 函数装饰 ```python def my_decorator(func): def wrapper(*args, **kwargs): print("Before the function is called.") result = func(*args, **kwargs) print("After the function is called.") return result return wrapper @my_decorator def say_hello(name): print(f"Hello, {name}!") say_hello("John") ``` 输出: ``` Before the function is called. Hello, John! After the function is called. ``` 2. 类装饰 ```python class MyDecorator: def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): print("Before the function is called.") result = self.func(*args, **kwargs) print("After the function is called.") return result @MyDecorator def say_hello(name): print(f"Hello, {name}!") say_hello("John") ``` 输出: ``` Before the function is called. Hello, John! After the function is called. ``` 3. 带参数的装饰 ```python def my_decorator(param): def decorator(func): def wrapper(*args, **kwargs): print(f"Before the function is called with {param}.") result = func(*args, **kwargs) print(f"After the function is called with {param}.") return result return wrapper return decorator @my_decorator("World") def say_hello(name): print(f"Hello, {name}!") say_hello("John") ``` 输出: ``` Before the function is called with World. Hello, John! After the function is called with World. ``` 4. 多个装饰的组合 ```python def my_decorator1(func): def wrapper(*args, **kwargs): print("Before the function is called by decorator 1.") result = func(*args, **kwargs) print("After the function is called by decorator 1.") return result return wrapper def my_decorator2(func): def wrapper(*args, **kwargs): print("Before the function is called by decorator 2.") result = func(*args, **kwargs) print("After the function is called by decorator 2.") return result return wrapper @my_decorator1 @my_decorator2 def say_hello(name): print(f"Hello, {name}!") say_hello("John") ``` 输出: ``` Before the function is called by decorator 1. Before the function is called by decorator 2. Hello, John! After the function is called by decorator 2. After the function is called by decorator 1. ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值