Proper use of lambda in function definition - python

I want to write a simple function that recognizes palindromes:
>>> def palindrome(s):
return s == s[::-1]
It works fine but it is case sensitive and to fix that I could do:
>>> def palindrome(s):
return s.lower() == s[::-1].lower()
>>> palindrome('Aba')
True
but I figure it's not very elegant. I tried to lowercase the input by using lambda expressions but I am doing something wrong and don't know how to fix it:
>>> def palindrome(lambda s : s.lower()):
return s == s[::-1]
SyntaxError: invalid syntax

You cannot use a lambda expression to describe actions that should be performed on input parameters (you can however use lambda to define a default value). You can do two things:
Define a function in the head of the function:
def palindrome(s):
s = s.lower()
return s == s[::-1]
Use a decorator:
def caseinsensitive(f):
def helper(s):
s = s.lower()
return f(s)
return helper
and then define your palindrome as:
#caseinsensitive
def palindrome(s):
return s == s[::-1]
Here you can reuse the #caseinsensitive to define all functions that do this as a first step.

Just call lower once, reassign s to the value and forget the lambda:
def palindrome(s):
s = s.lower()
return s == s[::-1]

This isn't really idiomatic python, but what you're looking for is something like this:
def palindrome(s):
return (lambda x: x == x[::-1])(s.lower())
That is, you define a lambda function and immediately invoke it, binding s.lower() to x.

def palindrome(s):
s = s.lower()
return s == s[::-1]
This is pretty straightforward and easy to use and understand answer, which is 100% correct and good.
BUT if you want to use lambda expression you must think how and what and why and stuff so let's go into the magical world of FUNCTIONAL PROGRAMMING.
If you don't know what a lambda expression is, basically when you type in the word lambda it specifies that you will later on give it some value for instance typing lambda a means you will supply it with 1 value (argument), typing lambda a, b explicitly means you will suppliy it with 2 values (arguments). So now that this whole thing of "what does even this lambda word mean" is done let's go deeper into the magical world of FUNCTIONAL PROGRAMMING.
So now when you tell python that it will have to wait some time (or maybe no time at all) for that value so it can do some magic on it, you can tell it what to do with it for instance
some_var = lambda some_string: some_string.lower()
So now this means that it's going to get some value, we expect it to be some sort of string and we can and will hold it in some_var for reasons only PHP programmers and us (me) know.
Next up is really straight forward we just return the check whether it is or not a palindrome
return some_var == some_var[::-1]
Let's get some glue and build this lambda beast from the things we have earlier
def palindrome():
some_var = lambda some_string : some_string.lower()
return some_var == some_var[::-1]
As you can see we no longer need to declare that we use some puny s in the method, hence we just press DEL and we can go along into the beatiful world of FUNCTIONAL PROGRAMMING.
So let's try to call this function, but the question raises how to do it?
palindrome("superpalindrome") == False
It does not compile though, because it thinks we are trying to give the palindrome method some kind of an argument while the definition has none at all. So the correct call of the function should be
palindrome()("superpalindrome") == False
In short, this is just magic, lambda expressions are actually in most cases worse in case of time usage, so you should stick to doing stuff in a OOP way or even else pythonic way. If you want to use lambda expressions you should try switching to Haskell(which I strongly advise) or Scala. If you have any further questions, feel free to ask me, I love talking about Haskell. Or FUNCTIONAL PROGRAMMING.
Full answer that is even more simplified
def palindrome():
return lambda some_str : some_str.lower() == some_str.lower()[::-1]
method = palindrome()
print(method("cococ"))

Maybe you wanted this:
(lambda lstr : lstr == lstr[::-1])((lambda x : x.lower())('abA'))

Related

Python: using a function that returns two items in an If statement, without executing twice

I have a function I'm using to test in an if/then.
The issue is that I'm executing the function BOTH in the if conditional, and then again after the if statement because the function returns two items.
This just seems wasteful and I'm trying to think of ways to improve this. Here's a really basic version of what I'm trying to avoid: "True" is returned to allow the condition to pass, but then then "coolstuff()" is executed again to get more information from the function.
"coolstuff()" could possibly return false, so I can't use the returned string "stuff" as the test.
def coolstuff():
return True, "stuff"
if coolstuff()[0]:
coolthing = coolstuff()[1]
print coolthing
There's gotta be a better way to do this, no? My brain is melting a little as I try to hash it out.
I basically want to do something like this (invalid) syntax:
def coolstuff():
return True, "stuff"
if a, b == coolstuff() and a:
print b
Just collect both results into variables
a, b = fn()
if a:
# work with b
def coolstuff():
if valid:
return "stuff"
return None
data = coolstuff()
if data:
print(data)
Call the function and capture the entire returned value:
x = coolstuff()
Now you have access to both parts of the returned value, in x[0] and x[1].
Store it:
state, coolvar = coolstuff()
if state:
do_whatever(coolvar)
If in newer Python, you could use the dreaded walrus (but I prefer ti7's approach of just assigning in a separate line):
if (x := coolstuff())[0]:
print(x[1])

lambda function in different lines

I am a complete newbie in python.
I start doing lambda functions and they end up a bit longer than my initial goal:
Can I split it in different lines for better readability?, like this:
parts.map(lambda p: (p[0]\
,p[1]\
,int(p[1].split("-")[0])\
,int(p[1].split("-")[1])\
,p[2]\
,float(p[3])\
,p[4]))
or it defeats the purpose of using a lambda function?
I feel when I write it is ok to use lambda function in one line, is quick and good, but when I check again my code later I feel is not legible all of it in one line...
If it's not clearly readable as a simple one-liner, then it's not a good candidate for a lambda. Remember that the lambda statement is just syntactic sugar, technically it IS a function:
>>> def foo(): pass
...
>>> bar = lambda: None
>>>
>>> type(foo)
<class 'function'>
>>> type(bar)
<class 'function'>
>>>
So yes, in your example it does definitly "defeat the purpose of using a lambda function". As far as I'm concerned, if I had to maintain this code, I'd rather find something like:
def prepare(p):
p1a, p1b = (int(x) for x in p[1].split("-"))
p3f = float(p3)
return p[0], p[1], p1a, p1b, p[2], p3f, p[4]
whatever = [prepare(part) for part in parts]
If you are interested in style and readability I can't recommend the PEP8 style guide enough. Overall, it explains the best practices to write readable Python.
It will in particular give you advice on where to put commas when you start a new line, when to use parenthesis and how and when to write to a new line.
On lambda functions in particular it states:
Always use a def statement instead of an assignment statement that
binds a lambda expression directly to an identifier.
Yes:
def f(x): return 2*x
No:
f = lambda x: 2*x
In your case, I would use a function instead.
You could define a normal function and just use it in the map function if it gets too long.
def foo(p):
'''your code'''
result = list(map(foo, your_list)) # the list wrapper to convert map object to a list

Pythonic way to Call a function with set of arguments until it return any thing but None

I know to use for loop and call my function till I get not None as return value, But I am looking for some python built in which can help here.
e.g. - iter(myfunc(), None) It will call myfunc() until it return None
I am looking to code exactly opposite to this e.g. - iter(myfunc(), not None), Call myfunc() until it returns any thing but None
Thanks in advance..
With just three lines:
x = None
while x is None:
x = f()
Do not look for a builtin for everything. In my opinion even the usual two-argument form of iter is not worth using because it's not a well known feature, and that makes it harder for most people to read. Just keep it simple and straightforward. An extra line or two will not hurt.
while True:
x = myfunc()
if x is not None:
break
There is no ready builtin, but it is easy enough to build a generator function:
def iter_while_none(f):
while True:
value = f()
if value is not None:
return
yield value
although the value yielded is not that interesting; it is, after all, None each time.
This answer is a bit of an exercise in the power of Python. I just get frustrated that iters 2-arity form doesn't take a function for its second parameter.
But it does, if you're crazy enough. See, you can redefine equality on an object, like so:
class Something:
def __eq__(self, other):
self.lastother = other
return other is not None
sentinel = Something()
myiter = iter(myfunc, sentinel)
for nope in myiter:
pass
match = sentinel.lastother
There. Enjoy. Python's pretty amazing that you can subvert the definition of equality this way. Have fun storming the castle!

Reduce a list using lambda

I need to write several functions like this. Is there a better way to write this function using lambda in one line or so.
def is_digital(offers):
for offer in offers:
digital = True if 'digital' in offer and offer['digital'] else False
if digital:
return True
return False
You can just use any for this.
def is_digital(offers):
return any(offer.get('digital') for offer in offers)
Or if you want to remove the full function definition and just use a lambda (not the best idea), you could do this:
is_digital = lambda offers: any(offer.get('digital') for offer in offers)
Thanks to jonrsharpe's comment for reminding me that .get is a thing.
As for me following way to check is more readable and explicit:
def is_digital(offers):
return any(map(lambda x: x.get('digital', False), offers))
you can even throw out default 'False', because 'None' is default return value if no specified key was found. But I think the code will become less explicit.
def is_digital(offers):
return any(map(lambda x: x.get('digital'), offers))
The choice is your. =)

Use an expression twice in one line - as a condition AND for string formatting?

I find that in lots of different projects I'm writing a lot of code where I need to evaluate a (moderately complex, possibly costly-to-evaluate) expression and then do something with it (e.g. use it for string formatting), but only if the expression is True/non-None.
For example in lots of places I end up doing something like the following:
result += '%s '%( <complexExpressionForGettingX> ) if <complexExpressionForGettingX> else ''
... which I guess is basically a special-case of the more general problem of wanting to return some function of an expression, but only if that expression is True, i.e.:
f( e() ) if e() else somedefault
but without re-typing the expression (or re-evaluating it, in case it's a costly function call).
Obviously the required logic can be achieved easily enough in various long-winded ways (e.g. by splitting the expression into multiple statements and assigning the expression to a temporary variable), but that's a bit grungy and since this seems like quite a generic problem, and since python is pretty cool (especially for functional stuff) I wondered if there's a nice, elegant, concise way to do it?
My current best options are either defining a short-lived lambda to take care of it (better than multiple statements, but a bit hard to read):
(lambda e: '%s ' % e if e else '')( <complexExpressionForGettingX> )
or writing my own utility function like:
def conditional(expr, formatStringIfTrue, default='')
... but since I'm doing this in lots of different code-bases I'd much rather use a built-in library function or some clever python syntax if such a thing exists
I like one-liners, definitely. But sometimes they are the wrong solution.
In professional software development, if the team size is > 2, you spent more time on understanding code someone else wrote than on writing new code. The one-liners presented here are definitely confusing, so just do two lines (even though you mentioned multiple statements in your post):
X = <complexExpressionForGettingX>
result += '%s '% X if X else ''
This is clear, concise, and everybody immediately understands what's going on here.
Python doesn't have expression scope (Is there a Python equivalent of the Haskell 'let'), presumably because the abuses and confusion of the syntax outweigh the advantages.
If you absolutely have to use an expression scope, the least worst option is to abuse a generator comprehension:
result += next('%s '%(e) if e else '' for e in (<complexExpressionForGettingX>,))
You could define a conditional formatting function once, and use it repeatedly:
def cond_format(expr, form, alt):
if expr:
return form % expr
else:
return alt
Usage:
result += cond_format(<costly_expression>, '%s ', '')
After hearing the responses (thanks guys!) I'm now convinced there's no way to achieve what I want in Python without defining a new function (or lambda function) since that's the only way to introduce a new scope.
For best clarity I decided this needed to be implemented as a reusable function (not lambda) so for the benefit of others, I thought I'd share the function I finally came up with - which is flexible enough to cope with multiple additional format string arguments (in addition to the main argument used to decide whether it's to do the formatting at all); it also comes with pythondoc to show correctness and illustrate usage (if you're not sure how the **kwargs thing works just ignore it, it's just an implementation detail and was the only way I could see to implement an optional defaultValue= kwarg following the variable list of format string arguments).
def condFormat(formatIfTrue, expr, *otherFormatArgs, **kwargs):
""" Helper for creating returning the result of string.format() on a
specified expression if the expressions's bool(expr) is True
(i.e. it's not None, an empty list or an empty string or the number zero),
or return a default string (typically '') if not.
For more complicated cases where the operation on expr is more complicated
than a format string, or where a different condition is required, use:
(lambda e=myexpr: '' if not e else '%s ' % e)
formatIfTrue -- a format string suitable for use with string.format(), e.g.
"{}, {}" or "{1}, {0:d}".
expr -- the expression to evaluate. May be of any type.
defaultValue -- set this keyword arg to override
>>> 'x' + condFormat(', {}.', 'foobar')
'x, foobar.'
>>> 'x' + condFormat(', {}.', [])
'x'
>>> condFormat('{}; {}', 123, 456, defaultValue=None)
'123; 456'
>>> condFormat('{0:,d}; {2:d}; {1:d}', 12345, 678, 9, defaultValue=None)
'12,345; 9; 678'
>>> condFormat('{}; {}; {}', 0, 678, 9, defaultValue=None) == None
True
"""
defaultValue = kwargs.pop('defaultValue','')
assert not kwargs, 'unexpected kwargs: %s'%kwargs
if not bool(expr): return defaultValue
if otherFormatArgs:
return formatIfTrue.format( *((expr,)+otherFormatArgs) )
else:
return formatIfTrue.format(expr)
Presumably, you want to do this repeatedly to build up a string. With a more global view, you might find that filter (or itertools.ifilter) does what you want to the collection of values.
You'll wind up with something like this:
' '.join(map(str, filter(None, <iterable of <complexExpressionForGettingX>>)))
Using None as the first argument for filter indicates to accept any true value. As a concrete example with a simple expression:
>>> ' '.join(map(str, filter(None, range(-3, 3))))
'-3 -2 -1 1 2'
Depending on how you're calculating the values, it may be that an equivalent list or generator comprehension would be more readable.

Categories