Usage of arithmetic operations on bool values True and False - python

In python, there is such a feature - True and False can be added, subtracted, etc
Are there any examples where this can be useful?
Is there any real benefit from this feature, for example, when:
it increases productivity
it makes the code more concise (without losing speed)
etc

While in most cases it would just be confusing and completely unwarranted to (ab)use this functionality, I'd argue that there are a few cases that are exceptions.
One example would be counting. True casts to 1, so you can count the number of elements that pass some criteria in this fashion, while remaining concise and readable. An example of this would be:
valid_elements = sum(is_valid(element) for element in iterable)
As mentioned in the comments, this could be accomplished via:
valid_elements = list(map(is_valid, iterable)).count(True)
but to use .count(...), the object must be a list, which imposes a linear space complexity (iterable may have been a constant space generator for all we know).
Another case where this functionality might be usable is as a play on the ternary operator for sequences, where you either want the sequence or an empty sequence depending on the value. Say you want to return the resulting list if a condition holds, otherwise an empty list:
return result_list * return_empty
or if you are doing a conditional string concatentation
result = str1 + str2 * do_concatenate
of course, both of these could be solved by using python's ternary operator:
return [] if return_empty else result_list
...
result = str1 + str2 if do_concatenate else str1
The point being, this behavior does provide other options in a few scenarios that isn't all too unreasonable. Its just a matter of using your best judgement as to whether it'll cause confusion for future readers (yourself included).

I would avoid it at all cost. It is confusing and goes against typing. Python being permissive does not mean you should do it ...

Related

Python-Z3: Python's assertion is not holding

I wanted to test whether the assert statement holds for z3 results.
To do so, I test the following statement: exists an integer x, such that for all integers y, (x>y). Which is false: there is no integer greater than the rest of the integers.
So I translate this to Z3py:
y_1 = Int('y_1')
x_1 = Int('x_1')
ttt = Tactic("qe")
w = Goal()
phi = Exists(x_1, ForAll (y_1, (x_1>y_1)))
w.add(phi)
result_ttt = ttt(w)
print(result_ttt)
As expected, the printed result is: [[False]]
So I test assert the following:
assert [[False]] == result_ttt
And, surprisingly, the result is assertion error!
Any help? Probably it has to do with the type of result_ttt being <class 'z3.z3.ApplyResult'> (after doing type(result_ttt).
Note that, analogously, if we choose a satisfiable statement the assertion does not hold either.
The chosen statement has been: for all integers x, exists integer y, (x>y). Which is true. In this case, the result is [[]] (since quantifier elimination is satisfactory). And when doing assert [[]] == result the result is negative.
When you write:
[[False]]
all that means is that you've a nested list with that element in it. Note that this has nothing to do with z3. It's a valid Python object.
Compare this to your result_tt, which is a Goal. So, you're trying to compare a Goal to a nested python list; and those two things are never going to be equal. They are completely different objects. Hence the assertion failure.
You're getting confused by the fact that these two things print the same way. But checking equality is an entirely different operation. If you really want to compare that they "print" the same, you can say something like:
assert '[[False]]' == obj_to_string(result_ttt)
But of course that's very ugly and is fragile in case z3 developers decide to change how goals are converted to strings later on.
In general, you shouldn't be trying to compare goals to anything else, and instead use a solver to prove them, or tactics to transform and eliminate them. Using them in any other way will be fragile and will likely not do what you want in the first place to start with.

When should I use a for loop or a while loop?

I am confused about when using a while-loop or for-loop is better? I am particularly worried about producing optimized answers to coding questions. I find myself solving problems just to find out a while-loop would've been faster but am confused about what leads people to choose to use it instead of a for-loop, like what criteria should I be looking for?
Here's an example of a coding question I answered which checks if a string of parentheses is balanced.
def parenCheck(str):
stack = Stack()
for x in str:
if x == '(':
stack.push(x)
else:
if stack.isEmpty():
return False
else:
stack.pop()
return stack.isEmpty()
Here is the answer I saw for it , which I know is faster because it doesnt use a for-loop:
def parChecker(symbolString):
s = Stack()
balanced = True
index = 0
while index < len(symbolString) and balanced:
symbol = symbolString[index]
if symbol == "(":
s.push(symbol)
else:
if s.isEmpty():
balanced = False
else:
s.pop()
index = index + 1
if balanced and s.isEmpty():
return True
else:
return False
For the same number of iterations, and content, my guess is that a for loop and wihile have practically the same speed. But I haven't tested that - mostly I answer numpy questions where we try to avoid either loop (preferring iterations in compiled code).
Your examples show the basic case where for results in cleaner, if not faster, code:
for x in an_iterator:
<do something>
versus
i = 0
while i < len(an_iterator):
x = an_iterator[x]
<do something>
i += 1
If you must have an index as well, you can use:
for i, x in enumerate(an_iterator):
....
That ability to iterate directly on things like lists and dictionaries was the main neat feature that caught my attention when I first saw Python in the 1990.
A common subcase of a for loop accumulates values, so common, that Python provides the popular list comprehension, and extended the syntax to generator expressions and dictionary comprehensions.
while still has its uses. Other languages have do while and do until variants, which attempt to streamline stepping the variable and testing. Python has just the one version with separate steps. The new walrus operator has the potential of cleaning that up:
https://docs.python.org/3/whatsnew/3.8.html#assignment-expressions
while (block := f.read(256)) != '':
process(block)
while is most useful when the steps aren't regular, or from a well defined iterator. for can break and continue, but otherwise the sequence is fixed (at the start of iteration).
In addition to enumerate, zip lets us iterate on several things at once.
The convenience of list comprehensions encourages us to decompose a complicated task into a sequence of comprehensions. And to make that even more convenient (and faster/memory efficient) Python provides generators and all sort so itertools. In Python 3, range and dictionary keys/items/values all became generator like expressions.
This cannot be decided by your code that while loop worked faster than for loop. As of your question on when to use while and for loop, it is decided on the basis of whether we know the number of iterations. If number of iterations is known, for loop is preferred, whereas while loop is preferred when the iterations are indefinite.
for (int i : mynumber_list)
Iterator it = mynumber_list.iterator()
while (it.hasNext())
As can be seen from above, for loop is more readable, simple, and easy in traversing. Moreover, iterator.hasNext() has a very high probability of entering into an infinite loop
while can also be useful for user choice input questions, like keep executing the program until the user presses any other key except y. This is difficult to achieve with for loop.

How could I use map() in this code?

I have a string list
[str1, str2, str3.....]
and I also have a def to check the format of the strings, something like:
def CheckIP(strN):
if(formatCorrect(strN)):
return True
return False
Now I want to check every string in list, and of course I can use for to check one by one. But could I use map() to make code more readable...?
You can map your list to your function and then use all to check if it returns True for every item:
if all(map(CheckIP, list_of_strings)):
# All strings are good
Actually, it would be cleaner to just get rid of the CheckIP function and use formatCorrect directly:
if all(map(formatCorrect, list_of_strings)):
# All strings are good
Also, as an added bonus, all uses lazy-evaluation. Meaning, it only checks as many items as are necessary before returning a result.
Note however that a more common approach would be to use a generator expression instead of map:
if all(formatCorrect(x) for x in list_of_strings):
In my opinion, generator expressions are always better than map because:
They are slightly more readable.
They are just as fast if not faster than using map. Also, in Python 2.x, map creates a list object that is often unnecessary (wastes memory). Only in Python 3.x does map use lazy-computation like a generator expression.
They are more powerful. In addition to just mapping items to a function, generator expressions allow you to perform operations on each item as they are produced. For example:
sum(x * 2 for x in (1, 2, 3))
They are preferred by most Python programmers. Keeping with convention is important when programming because it eases maintenance and makes your code more understandable.
There is talk of removing functions like map, filter, etc. from a future version of the language. Though this is not set in stone, it has come up many times in the Python community.
Of course, if you are a fan of functional programming, there isn't much chance you'll agree to points one and four. :)
An example, how you could do:
in_str = ['str1', 'str2', 'str3', 'not']
in_str2 = ['str1', 'str2', 'str3']
def CheckIP(strN):
# different than yours, just to show example.
if 'str' in strN:
return True
else:
return False
print(all(map(CheckIP, in_str))) # gives false
print(all(map(CheckIP, in_str2))) # gives true
L = [str1, str2, str3.....]
answer = list(map(CheckIP, L))
answer is a list of booleans such that answer[i] is CheckIP(L[i]). If you want to further check if all of those values are True, you could use all:
all(answer)
This returns True if and only if all the values in answer are True. However, you may do this without listifying:
all(map(CheckIP, L)), as, in python3, `map` returns an iterator, not a list. This way, you don't waste space turning everything into a list. You also save on time, as the first `False` value makes `all` return `False`, stopping `map` from computing any remaining values

What possible improvements can be made to a palindrome program?

I am just learning programming in Python for fun. I was writing a palindrome program and I thought of how I can make further improvements to it.
First thing that came to my mind is to prevent the program from having to go through the entire word both ways since we are just checking for a palindrome. Then I realized that the loop can be broken as soon as the first and the last character doesn't match.
I then implemented them in a class so I can just call a word and get back true or false.
This is how the program stands as of now:
class my_str(str):
def is_palindrome(self):
a_string = self.lower()
length = len(self)
for i in range(length/2):
if a_string[i] != a_string[-(i+1)]:
return False
return True
this = my_str(raw_input("Enter a string: "))
print this.is_palindrome()
Are there any other improvements that I can make to make it more efficient?
I think the best way to improvise write a palindrome checking function in Python is as follows:
def is_palindrome(s):
return s == s[::-1]
(Add the lower() call as required.)
What about something way simpler? Why are you creating a class instead of a simple method?
>>> is_palindrome = lambda x: x.lower() == x.lower()[::-1]
>>> is_palindrome("ciao")
False
>>> is_palindrome("otto")
True
While other answers have been given talking about how best to approach the palindrome problem in Python, Let's look at what you are doing.
You are looping through the string by using indices. While this works, it's not very Pythonic. Python for loops are designed to loop over the objects you want, not simply over numbers, as in other languages. This allows you to cut out a layer of indirection and make your code clearer and simpler.
So how can we do this in your case? Well, what you want to do is loop over the characters in one direction, and in the other direction - at the same time. We can do this nicely using the zip() and reversed() builtins. reversed() allows us to get the characters in the reversed direction, while zip() allows us to iterate over two iterators at once.
>>> a_string = "something"
>>> for first, second in zip(a_string, reversed(a_string)):
... print(first, second)
...
s g
o n
m i
e h
t t
h e
i m
n o
g s
This is the better way to loop over the characters in both directions at once. Naturally this isn't the most effective way of solving this problem, but it's a good example of how you should approach things differently in Python.
Building on Lattyware's answer - by using the Python builtins appropriately, you can avoid doing things like a_string[-(i+1)], which takes a second to understand - and, when writing more complex things than palindromes, is prone to off-by-one errors.
The trick is to tell Python what you mean to do, rather than how to achieve it - so, the most obvious way, per another answer, is to do one of the following:
s == s[::-1]
list(s) == list(reversed(s))
s == ''.join(reversed(s))
Or various other similar things. All of them say: "is the string equal to the string backwards?".
If for some reason you really do need the optimisation that you know you've got a palindrome once you're halfway (you usually shouldn't, but maybe you're dealing with extremely long strings), you can still do better than index arithmetic. You can start with:
halfway = len(s) // 2
(where // forces the result to an integer, even in Py3 or if you've done from __future__ import division). This leads to:
s[:halfway] == ''.join(reversed(s[halfway:]))
This will work for all even-length s, but fail for odd length s because the RHS will be one element longer. But, you don't care about the last character in it, since it is the middle character of the string - which doesn't affect its palindromeness. If you zip the two together, it will stop after the end of the short one - and you can compare a character at a time like in your original loop:
for f,b in zip(s[:half], reversed(s[half:])):
if f != b:
return False
return True
And you don't even need ''.join or list or such. But you can still do better - this kind of loop is so idiomatic that Python has a builtin function called all just to do it for you:
all(f == b for f,b in zip(s[:half], reversed(s[half:])))
Says 'all the characters in the front half of the list are the same as the ones in the back half of the list written backwards'.
One improvement I can see would be to use xrange instead of range.
It probably isn't a faster implementation but you could use a recursive test. Since you're learning, this construction is very useful in many situation :
def is_palindrome(word):
if len(word) < 2:
return True
if word[0] != word[-1]:
return False
return is_palindrome(word[1:-1])
Since this is a rather simple (light) function this construction might not be the fastest because of the overhead of calling the function multiple times, but in other cases where the computation are more intensive it can be a very effective construction.
Just my two cents.

String comparison in Python: is vs. == [duplicate]

This question already has answers here:
Why does comparing strings using either '==' or 'is' sometimes produce a different result?
(15 answers)
Closed 9 years ago.
I noticed a Python script I was writing was acting squirrelly, and traced it to an infinite loop, where the loop condition was while line is not ''. Running through it in the debugger, it turned out that line was in fact ''. When I changed it to !='' rather than is not '', it worked fine.
Also, is it generally considered better to just use '==' by default, even when comparing int or Boolean values? I've always liked to use 'is' because I find it more aesthetically pleasing and pythonic (which is how I fell into this trap...), but I wonder if it's intended to just be reserved for when you care about finding two objects with the same id.
For all built-in Python objects (like
strings, lists, dicts, functions,
etc.), if x is y, then x==y is also
True.
Not always. NaN is a counterexample. But usually, identity (is) implies equality (==). The converse is not true: Two distinct objects can have the same value.
Also, is it generally considered better to just use '==' by default, even
when comparing int or Boolean values?
You use == when comparing values and is when comparing identities.
When comparing ints (or immutable types in general), you pretty much always want the former. There's an optimization that allows small integers to be compared with is, but don't rely on it.
For boolean values, you shouldn't be doing comparisons at all. Instead of:
if x == True:
# do something
write:
if x:
# do something
For comparing against None, is None is preferred over == None.
I've always liked to use 'is' because
I find it more aesthetically pleasing
and pythonic (which is how I fell into
this trap...), but I wonder if it's
intended to just be reserved for when
you care about finding two objects
with the same id.
Yes, that's exactly what it's for.
I would like to show a little example on how is and == are involved in immutable types. Try that:
a = 19998989890
b = 19998989889 +1
>>> a is b
False
>>> a == b
True
is compares two objects in memory, == compares their values. For example, you can see that small integers are cached by Python:
c = 1
b = 1
>>> b is c
True
You should use == when comparing values and is when comparing identities. (Also, from an English point of view, "equals" is different from "is".)
The logic is not flawed. The statement
if x is y then x==y is also True
should never be read to mean
if x==y then x is y
It is a logical error on the part of the reader to assume that the converse of a logic statement is true. See http://en.wikipedia.org/wiki/Converse_(logic)
See This question
Your logic in reading
For all built-in Python objects (like
strings, lists, dicts, functions,
etc.), if x is y, then x==y is also
True.
is slightly flawed.
If is applies then == will be True, but it does NOT apply in reverse. == may yield True while is yields False.

Categories

Resources