1. I'm not sure what the problem is. In Python you can refer to "object.function" such that the result is kind of a Curried funtion where the "self" argument is implicit.

    Maybe an example would be better. In the following example, you can see that fb.foo and fb2.foo are two distinct functions, where "fb" is "self" for the first, and "fb2" is "self" for the second.

    Jython 2.1 on java1.4.1_01 (JIT: null)
    Type "copyright", "credits" or "license" for more information.
    >>> class FooBar:
    ... def foo(self):
    ... print self
    ... print "OK?"
    ...
    >>> fb = FooBar()
    >>> fb.foo()
    <__main__.FooBar instance at 17493979>
    OK?
    >>> fb2 = FooBar()
    >>> fb2
    <__main__.FooBar instance at 24940415>
    >>> fb2.foo()
    <__main__.FooBar instance at 24940415>
    OK?
    >> fb2.foo()
    <__main__.FooBar instance at 24940415>
    OK?
    >>> fb.foo

    >>> fb2.foo

    >>>
      posted by Patrick Logan at 07:57:43 PM on September 20, 2004  
  2. Yes, I am well aware of that. :-) The real "problem" is that there is no elegant way to grab a block of code and stick it in a certain context... e.g. a block of database code and make sure it's wrapped in a transaction. Or a with_open_file like in Lisp, etc. It's all possible in Python, it's just less easy than it could be (as demonstrated by languages like Groovy, Ruby, and of course Smalltalk and Lisp). It's no big deal really, just something I happen to run into today. :-)
      posted by Hans Nowak at 08:43:11 PM on September 20, 2004  
  3. Interesting. This is actually the first example I have seen of use of a code block where I haven't said to myself, "What's the big deal? I can do that in Python with a lambda expression."

    You can do what you want if you make make_transaction a non-member function and pass it an unbound member function as an argument. Then you can pick up 'self' as the first argument to the function created by make_transaction. I've posted a snippet here: http://pastebin.de/pastebin.py?id=1277

    This is deliciously twisted. Would work great as a Python 2.4 decorator.
      posted by Kent at 09:42:21 PM on September 20, 2004  
  4. You can do this in boo. There is an example of a custom "performtransaction" macro included.

    performTransaction connection:
    connection.Execute(cmd1)
    connection.Execute(cmd2)

    would get expanded to the full code block.

      posted by an anonymous coward at 10:50:40 PM on September 20, 2004  
  5. """Interesting. This is actually the first example I have seen of use of a code block where I haven't said to myself, "What's the big deal? I can do that in Python with a lambda expression.""""

    Same here. :) It makes me wish I could pass around and wrap arbitrary pieces of code. Currently that's only possible with functions or methods. Which is acceptable, most of the time, it just makes me wonder if there shouldn't be an easier way.
      posted by Hans Nowak at 11:10:29 PM on September 20, 2004  
  6. Stupid lambda tricks:

    You can't have real code blocks in Python, but if you like the style, you can use a simple hack to get around lambda's one-expression-only limitation: Python evaluates function arguments left to right, so you can do this:

    def do(*args):
    return args[-1]

    and now you can do this:

    def with_transaction(f):
    dbado.conn.BeginTrans()
    try:
    result = f()
    except:
    dbado.conn.RollBack()
    raise
    else:
    dbado.conn.Commit()
    return result

    and you can use it like this:

    results = with_transaction(lambda: do(
    insertSomething(),
    updateSomething(),
    selectSomething()
    ))

    Of course, it's not quite the same as a real code block (all the arguments to "do" have to be expressions, for instance), but you get the picture...


      posted by Bryn Keller at 03:20:48 AM on September 21, 2004  
  7. actually this is one of the things I like in ruby, and you actually happen to have replicated the ruby database interface
    dbcon.transaction do
    ...
    end

    I think that having a block construct in python like
    do vars:indentedblock | code

    would be a wonderful replacement for the current lambda form, but I'm afraid that has been debated so many times that it's impossible to see it.



      posted by gabriele at 09:16:20 AM on September 21, 2004  
  8. For my application I wrote a small Aspect thingy. Its on aspn too (http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/276629). You can create an Aspect class and apply it to the methods that need it. It should be pretty trivial to create a database transaction aspect.
      posted by Arjan Molenaar at 10:16:01 AM on September 21, 2004  
  9. Many years ago, on a Python conference somewhere in the US, Eric Raymond volunteered to come up with a syntax and a patch, and Guido said he's add it if it wasn't too ugly. So I suppose we're still waiting for Eric...
      posted by Fredrik at 05:28:18 AM on September 22, 2004  
  10. As far as I can tell it's undocumented, but...

    >>> f = FooBar()
    >>> f
    <__main__.FooBar instance at 0x013D5E40>
    >>> f.foo.im_self
    <__main__.FooBar instance at 0x013D5E40>

    It appears to be implementation-specific though.


      posted by Moof at 05:39:20 AM on September 22, 2004  
  11. why not just

    def with_transaction( class_fun ):
    ____def _with_transaction( self, *args, **kwargs):
    ________self.dbado.conn.BeginTrans()
    ________try:
    ____________result = class_fun(*args, **kwargs)
    ________except:
    ____________self.dbado.conn.RollbackTrans()
    ____________raise
    ________else:
    ____________self.dbado.conn.CommitTrans()
    ________return result

    ?
      posted by Florian at 06:03:48 AM on September 22, 2004  

  12. try this...

    def with_transaction(value):
    def test(self, *a, **b):
    self.db._beginTransaction()
    try:
    result = value(self, *a, **b)
    except MyExcept, e:
    self.db._abortTransaction()
    result = e.message
    else:
    self.db._endTransaction()
    return result
    return test

    class MyExcept(Exception):
    def __init__(self, message):
    self.message = message
    def __str__(self):
    return self.message

    class MyDb:
    def __init__(self):
    print "MyDb(%08x).__init__" % id(self)
    def _beginTransaction(self):
    print "MyDb(%08x)._beginTransaction" % id(self)
    def _endTransaction(self):
    print "MyDb(%08x)._endTransaction" % id(self)
    def _abortTransaction(self):
    print "MyDb(%08x)._abortTransaction" % id(self)
    def _work(self, parameter):
    print "MyDb(%08x)._work(%d)" % (id(self), parameter)
    if parameter == 456:
    raise MyExcept, "Error!"
    else:
    return "Ok (%d)!" % parameter

    class Test:
    def __init__(self):
    self.db = MyDb()
    def testMethod1(self, parameter):
    self.db._beginTransaction()
    try:
    result = self.db._work(parameter)
    except MyExcept, e:
    self.db._abortTransaction()
    result = e.message
    else:
    self.db._endTransaction()
    return result
    def testMethod2(self, parameter):
    return self.db._work(parameter)
    testMethod2 = with_transaction(testMethod2)
    def testMethod3(self, parameter1, parameter2=8):
    return self.db._work(parameter1*parameter2)
    testMethod3 = with_transaction(testMethod3)


    print "\nSTART"
    t = Test()
    result = t.testMethod1(123)
    print "result of testMethod1(123):", result
    result = t.testMethod2(123)
    print "result of testMethod2(123):", result
    result = t.testMethod1(456)
    print "result of testMethod1(456):", result
    result = t.testMethod2(456)
    print "result of testMethod2(456):", result
    result = t.testMethod3(55,7)
    print "result of testMethod3(12,13):", result
    result = t.testMethod3(56)
    print "result of testMethod3(56):", result
    result = t.testMethod3(57)
    print "result of testMethod3(57):", result
    print "END\n"


      posted by Vincenzo Palazzo at 06:34:02 PM on September 22, 2004  
  13. My last post has lose all the indentations...
    This is more clear :-)
    bye
      posted by Vincenzo Palazzo at 06:42:26 PM on September 22, 2004  
  14. I was just going to suggest what Florian said. Indeed what OP said "A decorator-like solution comes to mind, but the presence of self makes it impossible to do that at the class level:" is plain wrong, and such decorator-like solution is the best here.

    Though Florian forgot to return _with_transaction and pass self to class_fun.
      posted by Florian wannabe at 07:40:03 AM on October 03, 2004