1. 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').
      posted by Donovan Preston at 12:12:33 AM on September 23, 2004  
  2. 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.
      posted by Greg McClure at 01:36:29 PM on September 23, 2004  
  3. 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?
      posted by Andrew Brehaut at 11:22:16 PM on September 23, 2004  
  4. ack. sorry about that. i didnt realise it would kill my indentation.

    try this: http://pastebin.de/pastebin.py?id=1295
      posted by Andrew Brehaut at 11:24:28 PM on September 23, 2004  
  5. """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... :-}
      posted by Hans Nowak at 11:47:16 PM on September 23, 2004  
  6. 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.
      posted by Jonas Galvez at 03:39:58 AM on September 24, 2004  
  7. 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
      posted by gabriele at 08:20:59 AM on September 24, 2004  
  8. 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)


      posted by Greg Chapman at 09:07:12 PM on October 07, 2004  
  9. 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)

      posted by Greg Chapman at 09:23:24 PM on October 07, 2004  
  10. 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.
      posted by Hans Nowak at 09:39:14 PM on October 07, 2004  
  11. 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.

      posted by Greg Chapman at 11:50:21 AM on October 08, 2004