我发现函数与实例方法的decorator不能通用.

73 views
Skip to first unread message

李海珍

unread,
Jan 15, 2014, 3:58:24 AM1/15/14
to pyth...@googlegroups.com


def transaction(func):
    @functools.wraps(func)
    def _wrapper(*args, **kwargs):
        db.session.begin(subtransactions=True,nested=True)
        try:
            ret = func(*args, **kwargs)
            db.session.commit()
            return ret
        except Exception,e:
            db.session.rollback()
            log.trace()
            log.debug(e.message)
            raise e
    return _wrapper

def setup_transaction(func):
    def _wrapper(self,*args,**kwargs):
        db.session.begin(subtransactions=True,nested=True)
        try:
            ret = func(self,*args, **kwargs)
            db.session.commit()
            return ret
        except Exception,e:
            db.session.rollback()
            log.trace()
            log.debug(e.message)
            raise e
    return functools.update_wrapper(_wrapper, func)

我在数据模型CRUD的方法,将给方法一个decorator,
如上来来处理transaction的. 发现,如果是实例方法的话,要像下面一样来写decorator.

PS: 大家对于SQLAlchemy上,处理transaction 有什么最佳实践,或者建议吗?

Shell Xu

unread,
Jan 15, 2014, 4:24:35 AM1/15/14
to CUPG
那本来就是两种不同的函数定义吧,你要用同一种装饰器么?


2014/1/15 李海珍 <banx...@gmail.com>

--
--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
发言: pyth...@googlegroups.com
详情: http://code.google.com/p/cpyug/wiki/CpyUg
G+: https://plus.google.com/u/0/communities/108786798869709602787
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了 Google 网上论坛的“python-cn(华蟒用户组,CPyUG 邮件列表)”论坛。
要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到 python-cn+...@googlegroups.com
要查看更多选项,请访问 https://groups.google.com/groups/opt_out。



--
彼節者有間,而刀刃者無厚;以無厚入有間,恢恢乎其於游刃必有餘地矣。
blog: http://shell909090.com/blog/
about.mehttp://about.me/shell909090

limodou

unread,
Jan 15, 2014, 4:45:01 AM1/15/14
to Python.cn@google
我记得sqlalchemy的transcation支持with的用法。


2014/1/15 李海珍 <banx...@gmail.com>

--
--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
发言: pyth...@googlegroups.com
详情: http://code.google.com/p/cpyug/wiki/CpyUg
G+: https://plus.google.com/u/0/communities/108786798869709602787
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了 Google 网上论坛的“python-cn(华蟒用户组,CPyUG 邮件列表)”论坛。
要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到 python-cn+...@googlegroups.com
要查看更多选项,请访问 https://groups.google.com/groups/opt_out。



--
I like python!
UliPad <<The Python Editor>>: http://code.google.com/p/ulipad/
UliWeb <<simple web framework>>: https://github.com/limodou/uliweb
My Blog: http://my.oschina.net/limodou

Mo Mo

unread,
Jan 15, 2014, 5:48:19 AM1/15/14
to pyth...@googlegroups.com


2014/1/15 李海珍 <banx...@gmail.com>

--
--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
发言: pyth...@googlegroups.com
详情: http://code.google.com/p/cpyug/wiki/CpyUg
G+: https://plus.google.com/u/0/communities/108786798869709602787
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了 Google 网上论坛的“python-cn(华蟒用户组,CPyUG 邮件列表)”论坛。
要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到 python-cn+...@googlegroups.com
要查看更多选项,请访问 https://groups.google.com/groups/opt_out。



--
------
iMom0.
------

李海珍

unread,
Jan 15, 2014, 7:19:57 AM1/15/14
to pyth...@googlegroups.com
之前回复的,好像不见了(伤心)
那简单再写下:
看了,我的理解:
主要是在对于类实例方法的装饰器支持,
主要是利用了,
(1)Python的Descriptor特性的__get__方法
(2)functools 的partial 预填充实例方法的第一个参数(即self)来构造出新可调用对象.


PS1: 如果是类装饰器,应该使用functools.update_wrapper(self,func)来包装一下.

PS2: 如上,如果装饰的是已经有classmethod的的方法的话,应该先以如下的顺序:
@classmethod
@memoized
def func:pass

PS3: 你的提供的链接的文章的站点应该你的个人站,我提个小建议,
就是对于长度不是特别长的代码就不要用滚动条,嗯,比如原文中的class代码,虽然不长,但是也要去拉滚动条才能看到全部代码,
如果是全部显示,那就更好了.



在 2014年1月15日星期三UTC+8下午6时48分19秒,Mom0写道:

李海珍

unread,
Jan 15, 2014, 7:43:54 AM1/15/14
to pyth...@googlegroups.com
谢谢,是的,可以使用 with session.begin():
及相关的begin_nested() 方法.
PS:我知道前辈您是SQLAlchemy的大神,
有一个问题想借道问一下:
我下面的这样的demo:
session = session_factory()
demo = Demo(name='banxi')
try:
    with session.begin(subtransactions=True):
        session.add(demo)
        session.add(Demo(name='iyan'))
        raise Exception('test for exception')
except Exception,e:
    #session.rollback()
    print e.message


print session.query(Demo).all()

会报如下的错误:
  File "/home/banxi/Envs/learn-sqlalchemy/local/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 282, in _connection_for_bind
    self._assert_active()
  File "/home/banxi/Envs/learn-sqlalchemy/local/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 198, in _assert_active
    "This Session's transaction has been rolled back "
sqlalchemy.exc.InvalidRequestError: This Session's transaction has been rolled back by a nested rollback() call.  To begin a new transaction, issue Session.rollback() first.

取消捕获异常的rollback()才行.


在 2014年1月15日星期三UTC+8下午5时45分01秒,limodou写道:

flyer

unread,
Jan 15, 2014, 7:44:53 AM1/15/14
to python-cn

尝试用 decorator 库吧 ( https://pypi.python.org/pypi/decorator),它解决了写 decorator 过程可能遇到的问题

limodou

unread,
Jan 15, 2014, 8:03:33 AM1/15/14
to Python.cn@google
本人不是什么sqlalchemy大神,而且我用的sqlalchemy都相对底层一些。

从上面的异常描述是说,rollback已经执行了。所以我想with的处理应该是已经包括了回滚,所以你并不需要再次执行了吧。我的感觉。可以通过打印sqlalchemy的日志查看底层的sql语句,看是不是执行了。


2014/1/15 李海珍 <banx...@gmail.com>

李海珍

unread,
Jan 15, 2014, 8:14:17 AM1/15/14
to pyth...@googlegroups.com

嗯,我指的是需要我再手动执行一次rollback, 才OK的。所以我就不明白了。字面意思是一个嵌套的transaction 已经回滚了。需要再执行一次Session. rollback 来开始一个新的事务。来执行查询,有的不明白。
PS:你不算大神,谁算。

limodou

unread,
Jan 15, 2014, 8:17:00 AM1/15/14
to Python.cn@google
是不是和你那个参数有关系?


2014/1/15 李海珍 <banx...@gmail.com>

嗯,我指的是需要我再手动执行一次rollback, 才OK的。所以我就不明白了。字面意思是一个嵌套的transaction 已经回滚了。需要再执行一次Session. rollback 来开始一个新的事务。来执行查询,有的不明白。
PS:你不算大神,谁算。

--
--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
发言: pyth...@googlegroups.com
详情: http://code.google.com/p/cpyug/wiki/CpyUg
G+: https://plus.google.com/u/0/communities/108786798869709602787
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了 Google 网上论坛的“python-cn(华蟒用户组,CPyUG 邮件列表)”论坛。
要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到 python-cn+...@googlegroups.com
要查看更多选项,请访问 https://groups.google.com/groups/opt_out。

李海珍

unread,
Jan 15, 2014, 9:05:19 AM1/15/14
to pyth...@googlegroups.com
我好像明白是什么意思了:
我看Session的代码里的构造函数__init__方法中,会默认开始一个transaction.
sqlalchemy.orm.session.Session
中:
方法参数列表:
    def __init__(self, bind=None, autoflush=True, expire_on_commit=True,
                _enable_transaction_accounting=True,
                 autocommit=False, twophase=False,
                 weak_identity_map=True, binds=None, extension=None,
                 query_cls=query.Query):



        if not self.autocommit:
            self.begin()

所以在获得一个会话实例时,已经开始一个transaction了,
所以在我的demo中,再次使用session.begin()的话,如果不如subtransactions=True的话,
会有如下错误:
  File "/home/banxi/work/python/learn-sqlalchemy/session_base_tutorial.py", line 26, in test_session_with_syn
    with session.begin():
  File "/home/banxi/Envs/learn-sqlalchemy/local/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 648, in begin
    "A transaction is already begun.  Use "
InvalidRequestError: A transaction is already begun.  Use subtransactions=True to allow subtransactions.

而我当时开始出错之后,是使用了subtransactions=True.这个参数的.
所以with session.begin(subtransactions=True):pass
代码块结束之后,生成的subtransaction调用了rollback
也就是错误提示所指:
This Session's transaction has been rolled back by a nested rollback() call

感觉好像是:
必须:
session.begin() # main tx start
session.begin(subtransactions=True) # sub tx start
session.rollback()                        # sub end
session.rollback()                     # main tx end 
这个时候 没有了tx了,会马上自动启动一个.

是不是rollback必须与begin必须成对呢?



在 2014年1月15日星期三UTC+8下午9时17分00秒,limodou写道:

依云

unread,
Jan 15, 2014, 11:17:45 AM1/15/14
to pyth...@googlegroups.com
OT 一下,SQLAlchemy 的事务处理这么复杂么……psycopg2 2.5+ 的 with 语法很聪
明呀,完全不用自己去 commit 或者 rollback :-)
--
Best regards,
lilydjwg

Linux Vim Python 我的博客:
http://lilydjwg.is-programmer.com/
--
A: Because it obfuscates the reading.
Q: Why is top posting so bad?

李海珍

unread,
Jan 15, 2014, 6:25:52 PM1/15/14
to pyth...@googlegroups.com

SA也可以用with语法。应该不负责,可能是我比较笨,理解有偏差。

limodou

unread,
Jan 15, 2014, 11:15:40 PM1/15/14
to Python.cn@google
我在uliweb中没有使用session,所以没有用过上面的方式。


2014/1/16 李海珍 <banx...@gmail.com>

SA也可以用with语法。应该不负责,可能是我比较笨,理解有偏差。

--
--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
发言: pyth...@googlegroups.com
详情: http://code.google.com/p/cpyug/wiki/CpyUg
G+: https://plus.google.com/u/0/communities/108786798869709602787
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了 Google 网上论坛的“python-cn(华蟒用户组,CPyUG 邮件列表)”论坛。
要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到 python-cn+...@googlegroups.com
要查看更多选项,请访问 https://groups.google.com/groups/opt_out。
Reply all
Reply to author
Forward
0 new messages