-
You still want your code blocks, trust me. You can use decorators and named closures until you are blue in the face, but they will still remain workarounds just because python doesn't have a convenient anonymous multi-line block syntax.
Smalltalk really shows you why, too. All control flow constructs are implemented in terms of blocks -- which means if you want to design your own control flow construct it is easy to do so. Take "if":
true ifTrue: [Transcript write: 'Hello'].
true is the singleton object representing a true value. ifTrue: is simply a method on this object which takes a single block and evaluates it. Something like (1 = 2) evaluates to the singleton false object, which does not execute a block passed to ifTrue:.
Anyway, blocks are awesome, and once you use a language that has them you miss them. What you seem to want in the post is more like an aspect, though ('around').
-
It is ironic that in a language built around a syntax of code blocks there's no such thing as actual code blocks. Well, there's always that mutant daughter of Python and Perl: Ruby.
-
Im not entirely sure this is what you want but i hacked up (and i really do mean hacked, its not at all nice) a CodeBlock class that might do what you want, in a similar way to what i understand you want. its basicly a lambda that can have statements in it.
"""
This package attempts to implement code blocks in python
"""
__author__ = "Andrew Brehaut"
__copyright__ = "Copyright (c) 2004, Andrew Brehaut"
__version__ = "0.1"
import StringIO
class CodeBlock(object):
def __init__(self, codestring, *keys):
"""codestring is a string of python code"""
self._source = codestring
self._keys = keys
if codestring:
codestring = StringIO.StringIO(codestring)
c = "def func():\n"
for l in codestring.readlines():
c += " " + l + "\n"
c += "\n__return__ = func()\n"
codestring = c
self._block = compile(codestring, "CODEBLOCK", 'exec')
else:
self._block = None
def __call__(self, *args, **kargs):
"""make this a callable object, so it can be used as a codeblock"""
if self._block:
if len(args) <= len(self._keys):
for i in range(len(args)):
kargs[self._keys[i]] = args[i]
kargs['__return__'] = None;
exec (self._block, kargs)
return kargs['__return__']
else:
return None
To use this, you can just go:
from CodeBlock import CodeBlock
b = CodeBlock("""print "an Example " + foo
for i in range(4)
print i * bar
return "This is a return!!"
""", 'foo', 'bar')
b('hello, world!', 200)
is this what you want roughly?
-
ack. sorry about that. i didnt realise it would kill my indentation.
try this: http://pastebin.de/pastebin.py?id=1295
-
"""is this what you want roughly?"""
Not precisely. :-) It's interesting, but what I'm after is not the fact that a codeblock can be reused... after all, so can functions, methods, etc... but that it can be used "ad hoc".
Think of a try..except block. try has a code block, so does except. Now think of how much trouble it would be to use these if you couldn't use code blocks there, but had to use functions or methods.
Similarly, in some situations I've been missing the ability to use code blocks. with_transaction is just an example. Let's say you have some database code and want to do all that in one transaction. You cannot just indent the code and add a line with transaction t: (or something) at the top. Rather, you have to put your code in a function/method, then use clumsy constructs like functions returning functions, or descriptors.
This is not an extremely important issue... after all, it *can* be done. It's just less easy than it could be. So I'd say it's an area that could use some improvement. Who knows, maybe in Python 3000... :-}
-
Would Guido consider something like the following?
def method(str):
yield str, 1, 2, 3
method('test')|str, a, b, c|:
print str, a, b, c
In Ruby, that'd be:
def method(str)
yield str, 1, 2, 3
end
method('test') {
|str, a, b, c| puts str, a, b, c
}
Or, in JavaScript:
function test(f, str) {
f(str, 1, 2, 3)
}
test('test', function(str, a, b, c) {
alert(str, 1, 2, 3);
});
Pretty clean, but I really dislike braces.
-
this would be awful cause you'd override yield functionality, imo. Python has a convenient function calling syntax, in someblock(someargs) what is needed is just a nifty syntax for lambdas/blocks/anonymous functions/closure/name of the day
-
In your discussions of various workarounds for the lack of code blocks, I don't see what seems like one of the more direct analogues available from python (oversight or dislike?):
class Blah:
def with_transaction(self, f):
BeginTrans()
try:
result = f()
except:
RollbackTrans()
raise
else:
CommitTrans()
return result
def insert_foo(self, foo):
def block():
# arbitrary database code
return self.with_transaction(block)
-
Ugh, stripping leading whitespace seems rather unfiendly for a Python blog (this blogging software could use a preview feature like in the Python Cookbook). Anyway, the general idea was the following, where with_transaction calls block once the transaction is set up (hopefully, this formats correctly):
class Blah:
def insert_foo(self, foo):
def block():
# arbitrary database code
return self.with_transaction(block)
-
That would be a possibility too, although this solution requires a special construct in insert_foo, while the other ones use a "regular" method and then use wrappers around it. Not that it matters much, it's just as valid.
-
By the way, I'd forgotten about this:
http://www.python.org/peps/pep-0310.html
which would (I think) serve very nicely, provided some sort of exception-handling extension was added.