Scott, in your “Functional Python” introduction you write:
The one limitation that most disappoints me is that Python lacks is a functional way of writing if/else. Sometimes you just want to do something like this:
lambda x : if_else(x>100, “big number”, “little number”)(This would return the string “big number” if x was greater than 100, and “little number” otherwise.) Sometimes I get around this by defining my own if_else that I can use in lambda-functions:
def if_else(condition, a, b) : if condition : return a else : return b
Actually, you don’t need this helper if_else function at all:
In [1]: f = lambda x: x > 100 and 'big' or 'small'
In [2]: for i in (1, 10, 99, 100, 101, 110): ...: print i, 'is', f(i) ...: 1 is small 10 is small 99 is small 100 is small 101 is big 110 is big
James, obviously you’re right… Stupid me didn’t think about that. Your version won’t work when a discriminator isn’t known at import time. But even then a function taking *args and **kwargs with a class-like name, returning a correct class instance, would cut the job.
Regarding the module/plugin stuff, I’d rather use setuptools/pkg_resources
If you can use Python2.5 features, a “Conditional Expression” (http://docs.python.org/whatsnew/pep-308.html) is the just the right tool.
f = lambda x: ‘big’ if x > 100 else ‘small’
Eduardo: didn’t know about that one. I’m still on 2.4 though, both on my personal machine as in our development environment.
Or you can write it as
f = lambda x: ['small', 'big'][x>100]
Either is pretty ugly, though, and doesn’t read like a real “if-then”. Something I really miss from Perl is being able to declare arbitrary anonymous functions wherever I feel like it.
Thomas: BAH!
Nicolas: The simplified version of your metaclass example was functionally equivalent. If you did not know the discriminator at import time, your original version wouldn’t have worked either.
James: I thought the metaclass’ __new__ method is called on every instanciation?
00:55 <ikke> jamesh: isnt __new__ executed on every instanciation?
00:55 @<jamesh> ikke: yes, but you had a __new__ on the metaclass
00:55 @<jamesh> ikke: which is executed when you created a new class
Obviously :-/ Thanks James!
Be very very careful about this X and Y or Z trick. It fails miserably when bool(Y) is False.
Looks like there’s no real solid solution short of a helper function – like Marius said, ( and or ) fails if evaluates to False (the inverse, or and , is even worse), and Thomas’ [, ][not ]) will always evaluate both and , which can be problematic…
I’m starting to long for the ?: of c
so after reading this it also means u could just do
condition and “True statement” or “Falsestatement”
which seams the easyest solution
I personally liked the ‘and’ ‘or’ idea. What’s wrong about it?
The “And”/”Or” solution doesn’t work in any case. At least, I didn’t manage to make it work.
For example, if your “True statement” is actually a value which is evaluated to a “False” expression(like 0, None, ” or []) then “False statement” will always be returned.
example:
print (lambda x:x==2 and 0 or 1)(2) —> 1
print (lambda x:x==2 and 0 or 1)(3) —> 1
Even worst, if one of the “True/False statements” cannot be evaluated to a boolean expression(like a numpy.array) then it won’t work at all…
example:
print (lambda x:x==2 and numpy.array([3,4]) or 1)(2)
Any idea to circumvent such problems??
>>> print (lambda x: 0 if x == 2 else 1)(2)
0
>>> print (lambda x: 0 if x == 2 else 1)(3)
1
>>> print (lambda x: np.array([3, 4]) if x == 2 else 1)(2)
[3 4]
(lambda x: x!=2 and 1 or 0)
Such an important article. God, this was killing me.
I liked this article especially Eduardo de Oliveira Padoan comment