syntax for code blocks

alex23 wuwei23 at gmail.com
Tue May 1 22:43:57 EDT 2012


[Apologies in advance if this comes through twice]

On May 2, 12:18 am, Kiuhnm <kiuhnm03.4t.yahoo.it> wrote:
> "Most Pythonic" doesn't mean better, unfortunately.

Nor does it mean "Kiuhnm prefers it".

> For instance, assume that you want to write a function that accepts a
> dictionary of callbacks:
>    func(some_args, callbacks)
>
> Pythonic way
> ------------
>
> def when_odd(n):
>      pass
>
> def when_prime(n):
>      pass
>
> def before_check():
>      pass
>
> def after_check():
>      pass
>
> func(some_args, {'when_odd' : when_odd,
>                   'when_prime' : when_prime,
>                   'before_check' : before_check,
>                   'after_check' : after_check})

When would you _ever_ define a function like this? Why are you passing
in _named_ callbacks? Are you calling them by name? Then declare them
in the function signature and rely on scoping. Does func() branch on
existent keys? Then don't write code like that.

At the very _least_, you could change the function call to:

    func(some_args, locals())

But as you're _passing them in by name_ why not just make it
func(some_args) and pick them up out of the scope.

_No one_ writes Python code like this. Presenting bad code as
"pythonic" is a bit of a straw man.

> My way
> ------
>
> with func(some_args) << ':dict':
>      with when_odd as 'n':
>          pass
>      with when_prime as 'n':
>          pass
>      with before_check as '':
>          pass
>      with after_check as '':
>          pass

This is unintuitive, to say the least. You're effectively replacing
the common form of function definition with "with when_odd as 'n'",
then using the surrounding context manager to limit the scope.

More importantly, _you're naming your "anonymous" code blocks_, I'm
guessing so that func() can choose which ones to use. But if you're
naming them, why not just use a function?

I'm not entirely sure what your 'solution' offers over something like:

class FOO(object):
    def __init__(self, fn):
        self.fn = fn

    def __enter__(self):
        return self.fn

    def __exit__(self, exc_type, exc_value, traceback):
        pass

def func(x, before_check=None, after_check=None, when_odd=None,
when_prime=None):
    pass

with FOO(func) as f:
    def before_check(x):
        pass
    def after_check(x):
        pass
    def when_odd(x):
        pass
    def when_prime(x):
        pass

    f(1)

I called the context manager FOO because I couldn't think of a more
appropriate name (contextscope?)...which is fair, as I can't think of
a use for it either. If you want to automate the function call at the
context manager exit, use something like this instead:

class FOO(object):
    def __init__(self, fn, *args, **kwargs):
        self.fn = fn
        self.args = args
        self.kwargs = kwargs

    def __enter__(self):
        f = inspect.currentframe(1)
        self.scope_before = dict(f.f_locals)

    def __exit__(self, exc_type, exc_value, traceback):
        f = inspect.currentframe(1)
        scope_after = dict(f.f_locals)
        scope_context = set(scope_after) - set(self.scope_before)
        clocals = dict(
            [(k, scope_after[k]) for k in scope_context]
        )
        self.kwargs.update(clocals)
        self.fn(*self.args, **self.kwargs)

Maybe there is a compelling use case for code blocks but your toy
example certainly isn't it.



More information about the Python-list mailing list