-
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
>>>
-
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. :-)
-
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.
-
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.
-
"""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.
-
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...
-
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.
-
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.
-
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...
-
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.
-
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
?
-
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"
-
My last post has lose all the indentations...
This is more clear :-)
bye
-
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.