Python的装饰器和with语法

本文介绍了Python中装饰器的基本概念及其使用方法,并探讨了如何利用装饰器为函数添加额外的功能。此外,还讲解了with语法的应用场景及其实现原理,包括如何创建上下文管理器以及如何使用with语法简化资源管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值