[Python-ideas] variable binding [was lambda decorators]

Guido van Rossum guido at python.org
Tue Feb 10 01:55:03 CET 2009


On Mon, Feb 9, 2009 at 4:46 PM, Carl Johnson <carl at carlsensei.com> wrote:
> The proposal to add bind to the function definition is silly, since we can
> do the equivalent of def f(bind i, …) already using decorators:
>
>>>> class bind(object):
> ...     def __init__(self, *args, **kwargs):
> ...         self.args, self.kwargs = args, kwargs
> ...
> ...     def __call__(self, f):
> ...         def inner(*args, **kwargs):
> ...             return f(self, *args, **kwargs)
> ...         return inner
> ...
>>>> l = []
>>>> for i in range(10):
> ...     @bind(i)
> ...     def my_func(bound_vars, *args, **kwargs):
> ...         return bound_vars.args[0]
> ...     l.append(my_func)
> ...
>>>> [f() for f in l]
> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>> [f() for f in l]
> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>
> Just put the bind decorator into functools and the problem is solved. This
> is better than the (UGLY!) default values hack, since in this case it is
> impossible for your caller to accidentally overwrite the value you wanted
> bound (or at least not without some stackframe manipulation, at which point
> you get what you deserve).

Sure, if you want to manufacture a whole new object each time through
the loop and access the bound variable by digging deep into an extra
argument, this might be considered less ugly. Personally if I had to
go to such lengths I would prefer to just switch to an OO style of
coding and make the function a genuine method (effectively you're
making it a method anyway by implicitly passing self).

As others implied, I don't see why you should go to such lengths to
avoid having to write OO code.

-1 on adding this UGLY hack to functools.

> I also don't like Guido's proposed var and new keywords. With all due
> respect, it looks like JavaScript. Besides, we all ready have a perfectly
> good tool for adding new scopes: functions. Just use a decorator like this
> map_maker to make an imap of the for-loop you wanted to have a separate
> scope in.

I guess UGLY is subjective. :-)

>>>> class map_maker(object):
> ...     def __init__(self, f):
> ...         self.f = f
> ...
> ...     def __call__(self, seq):
> ...         return (self.f(item) for item in seq)
> ...
>>>> a = 1
>>>>
>>>> @map_maker
> ... def my_map(a):
> ...     print("Look ma, the letter a equals", a)
> ...
>>>> list(my_map(range(10)))
> Look ma, the letter a equals 0
> Look ma, the letter a equals 1
> Look ma, the letter a equals 2
> Look ma, the letter a equals 3
> Look ma, the letter a equals 4
> Look ma, the letter a equals 5
> Look ma, the letter a equals 6
> Look ma, the letter a equals 7
> Look ma, the letter a equals 8
> Look ma, the letter a equals 9
> [None, None, None, None, None, None, None, None, None, None]
>>>>
>>>> a
> 1

Such games with decorators look UGLY to me. How I am, poor reader,
supposed to guess what the signature of my_map() is from reading its
definition?

> So, my proposal is that the API of the bind decorator be cleaned up
> considerably then added to the functools. The map_maker API seems to be good
> enough and could also go into functools.

-1 again.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)



More information about the Python-ideas mailing list