Confessions of a Python fanboy

Masklinn masklinn at masklinn.net
Fri Jul 31 21:24:33 CEST 2009


On 31 Jul 2009, at 20:17 , Steven D'Aprano wrote:
> On Fri, 31 Jul 2009 18:15:15 +0200, Masklinn wrote:
>
>>> I know, I know, Ruby people swear by
>>> anonymous code blocks, and I've read Paul Graham too. But I'm really
>>> not so sure that the benefits of anonymous code blocks are great
>>> enough to overcome the disadvantages of anonymous code blocks.
>>>
>> What are the disadvantages of anonymous functions?
>
> In no particular order, and not necessarily exhaustive:
>
> * The risk of obfuscation in your code. That's fairly minimal for
> lambdas, because they're just a single expression, but for a large
> anonymous code block (ACB) defined inside a named function, it may be
> difficult for the reader to easily distinguish which bits are the  
> outer
> function and which are the ACB.
>
I believe that one's unadulterated BS.

> * Loss of useful debugging information. Take this example from Python:
>
>>>> def main(f):
> ...     return f(3)
> ...
>>>> main(lambda n: 2/(n-3))
> Traceback (most recent call last):
>  File "<stdin>", line 1, in <module>
>  File "<stdin>", line 2, in main
>  File "<stdin>", line 1, in <lambda>
> ZeroDivisionError: integer division or modulo by zero
>>>>
>>>> def my_special_function(n):
> ...     return 2/(n-3)
> ...
>>>> main(my_special_function)
> Traceback (most recent call last):
>  File "<stdin>", line 1, in <module>
>  File "<stdin>", line 2, in main
>  File "<stdin>", line 2, in my_special_function
> ZeroDivisionError: integer division or modulo by zero
>
> If your code has only one anonymous function (whether a lambda or a  
> full
> multi-line block), then it's easy to identify which lambda raised the
> exception: there is only one it could be. But if your code uses lots  
> of
> lambdas, the lack of a function name makes it hard to distinguish one
> <lambda> from another <lambda>. Anonymity makes identification harder.
>
The traceback gives you the line of the anonymous function (even in  
python) so unless you have several anonymous functions on the same  
line, there's no reason why that would be much of an issue.  
Furthermore, Python doesn't provide any more information when the  
error happens out of a function (in a `for` or a `with`), so it's not  
like there's much of a difference here between Ruby's block-based  
approach and Python's statements-based approach.

> * Risk of code-duplication and breaking the principle of Once And Only
> Once. Anonymous functions are generally created, used, then  
> immediately
> thrown away -- or at least made more-or-less inaccessible for reuse.  
> An
> anonymous function stored in a callback still exists, but the coder  
> isn't
> able to easily re-use it for another callback somewhere else in the  
> code.
> Consequently, there's a temptation for the coder to write the same
> function multiple times:
>
> add_button("Parrot", colour=blue, callback=lambda x: x.stuff('a'))
> add_button("Cheese", flavour=tasty, callback=lambda x: x.thing('b'))
> add_button("Canary", colour=yellow, callback=lambda x: x.stuff('a'))
>
> instead of:
>
> def bird_callback(x):
>    return x.stuff('a')
>
> add_button("Parrot", colour=blue, callback=bird_callback)
> add_button("Cheese", flavour=tasty, callback=lambda x: x.thing('b'))
> add_button("Canary", colour=yellow, callback=bird_callback)
>
Yes, that one I can give you though I don't think that's a big issue.  
And it's not like it's hard to extract the anonymous function into a  
named one and then use that on the third strike, so I really don't  
believe that point holds much water.

> * Recursion is more or less impossible without fragile tricks.
>
> (At least for Python. I don't know how recursion operates in Ruby.)
Code blocks are rarely if ever used recursively. If an operation is  
using anonymous functions recursively, then there's often something  
very wrong with the idea leading to that code. So I find this  
objection irrelevant.



More information about the Python-list mailing list