I have always thought that using -1 in a condition is alway the same as the writing False (boolean value). But from my code, I get different results:
Using True and False:
def count(sub, s):
count = 0
index = 0
while True:
if string.find(s, sub, index) != False:
count += 1
index = string.find(s, sub, index) + 1
else:
return count
print count('nana', 'banana')
Result: Takes to long for interpreter to respond.
Using 1 and -1:
def count(sub, s):
count = 0
index = 0
while 1:
if string.find(s, sub, index) != -1:
count += 1
index = string.find(s, sub, index) + 1
else:
return count
print count('nana', 'banana')
Result: 1
Why does using -1 and 1 give me the correct result whereas using the bool values True and False do not?
string.find doesn't return a boolean so string.find('banana', 'nana', index) will NEVER return 0 (False) regardless of the value of index.
>>> import string
>>> help(string.find)
Help on function find in module string:
find(s, *args)
find(s, sub [, start [, end]]) -> int
Return the lowest index in s where substring sub is found,
such that sub is contained within s[start,end]. Optional
arguments start and end are interpreted as in slice notation.
Return -1 on failure.
>>>
Your example simply repeats:
index = string.find('banana', 'nana', 0) + 1 # index = 3
index = string.find('banana', 'nana', 3) + 1 # index = 0
The -1 version works because it correctly interprets the return value of string.find!
False is of type bool, which is a sub-type of int, and its value is 0.
In Python, False is similar to using 0, not -1
There's a difference between equality and converting to a boolean value for truth testing, for both historical and flexibility reasons:
>>> True == 1
True
>>> True == -1
False
>>> bool(-1)
True
>>> False == 0
True
>>> bool(0)
False
>>> True == 2
False
>>> bool(2)
True
I have always thought that using -1 in a condition is alway the same as the writing False (boolean value).
1) No. It is never the same, and I can't imagine why you would have ever thought this, let alone always thought it. Unless for some reason you had only ever used if with string.find or something.
2) You shouldn't be using the string module in the first place. Quoting directly from the documentation:
DESCRIPTION
Warning: most of the code you see here isn't normally used nowadays.
Beginning with Python 1.6, many of these functions are implemented as
methods on the standard string object. They used to be implemented by
a built-in module called strop, but strop is now obsolete itself.
So instead of string.find('foobar', 'foo'), we use the .find method of the str class itself (the class that 'foobar' and 'foo' belong to); and since we have objects of that class, we can make bound method calls, thus: 'foobar'.find('foo').
3) The .find method of strings returns a number that tells you where the substring was found, if it was found. If the substring wasn't found, it returns -1. It cannot return 0 in this case, because that would mean "was found at the beginning".
4) False will compare equal to 0. It is worth noting that Python actually implements its bool type as a subclass of int.
5) No matter what language you are using, you should not compare to boolean literals. x == False or equivalent is, quite simply, not the right thing to write. It gains you nothing in terms of clarity, and creates opportunities to make mistakes.
You would never, ever say "If it is true that it is raining, I will need an umbrella" in English, even though that is grammatically correct. There is no point; it is not more polite nor more clear than the obvious "If it is raining, I will need an umbrella".
If you want to use a value as a boolean, then use it as a boolean. If you want to use the result of a comparison (i.e. "is the value equal to -1 or not?"), then perform the comparison.
Related
Code
def addition(num):
if num:
return num + addition(num - 1)
else:
return 0
res = addition(10)
print(res)
Explanation
I know what the function is doing:
it is a recursive function
I just don't know what if num: means or the else part.
I am guessing it means as long as the num is int do what is inside the if, else return 0.
Question
Can someone tell me what this code means?
if variable: and truthyiness
See the boolean values and Python's Truth Value Testing:
What is Truthy and Falsy? How is it different from True and False?
You can evaluate truthy and falsy values using the bool() conversion-function:
print('None:', bool(None))
print('zero:', bool(0))
print('negative:', bool(-1))
print('positive:', bool(1))
if num: mets if num is defined and unequal to 0:
is defined: num is not None
and is not zero: num != 0
bool(0) is False. The opposite condition is tested by if not num.
The role of if in a recursive function
It's a recursive function which calls itself until exit-condition num == 0 is met in the else branch. Then it simply returns 0. So, the role of if num: is the continue-condition opposed to an exit-condition.
You could also write it as exit-condition:
def addition(num):
if not num: # equivalent to: if num == 0 or num is None
return 0 # return 0 if exit-condition met
# default behavior: recurse until zero met
return num + addition(num - 1)
See also:
recursive factorial function
Basics of recursion in Python
Edge-cases for input
Note, how input of None and other falsy values return a zero.
Please also consider the edge-case of negative input, as Fred commented. Could (silently) return 0 to abort addition. Also might raise an error to warn about misuse, like:
if num < 0:
raise ValueError("Can not calculate the recursive-sum for negative values.")
What happens if a float like 10.5 is given as input?
It would step through each -1 decrease until 0.5. The next call of addition(-0.5) would jump over the num == 0 exit-condition and cause infinite recursion, even a stackoverflow.
Python and many other languages have a concept of "falsy", which roughly means "values that are treated as False when evaluated as a boolean". In Python, values that are falsy include empty collections such as empty lists, strings, sets, tuples, and dicts, the int or float 0, and None. I may be missing some here, and you may find that some classes are designed to be treated as falsy as well under certain conditions. There are also "truthy" values which evaluate to True is a boolean context. It's easy to find out if a value is truthy or falsy. Simply call bool() on it:
bool(0.0)
# False
In the context of your code, when 0 is reached, that will be evaluated as falsy, triggering the exit condition.
if num: means if num is different than 0 : if num!=0.
you better remove the else statement.
def addition(num): if num: return num + addition(num - 1) return 0
python already knows that return is an else statement.
here's a playlist of one of the bests on youtube by corey to learn & become at python : https://www.youtube.com/watch?v=YYXdXT2l-Gg&list=PL-osiE80TeTskrapNbzXhwoFUiLCjGgY7
and also I recommend this book, automating the boring stuff with python. it's free : https://automatetheboringstuff.com/
I have a code that checks if a given list of integers can sum up to a specified target. If any combination of the integers in a list can sum up to a target value, it returns True. The input 'start' is the index of the list that I want to start from and continue until the end of the list
def groupSum(start, nums, target):
if start >= len(nums):
return target == 0
else:
return groupSum(start + 1, nums, target - nums[start]) or groupSum(start + 1, nums, target);
So, if I put
groupSum(0, [2,4,8], 10)
it will return True, and, if I put
groupSum(0, [2,4,8], 9)
it will return False
QUESTION: I don't understand how they can put 'or' in the return statements, in a recursive case. I don't see how that's actually working. Is it passing multiple functions simultaneously to check every combination or what?
I'm pretty new to Recursion method and would appreciate it if you can explain the technique used here. Thanks
In python and and or operators, do not return boolean values. They return the last thing evaluated. So, when you
return a or b
if a is a truthy value, a will be returned. Otherwise, the truthness of the expression depends on b, and so b will be returned.
Why it's True for 10 is because there's an exact match for 10 (8+2); which your recursive function reduces to 0 for the target variable.
So, groupSum(start + 1, nums, target - nums[start]) this becomes True - so the comparison will be True or False, which will turn out to True!
Now, for the value of 9, there's no such match and hence it'll always remain False.
You can try for 12 and 6 as well. It'll return True.
Whereas, for any other value the comparison will always be False or False.
The following codes
multiples = []
for i in range(1,1000):
if i % 3 == 0 or i % 5 == 0:
multiples.append(i)
addition = sum(multiples)
print addition
and
print(sum([i for i in range(1, 1000) if not (i%3 and i%5)]))
do the same thing.
Now how does the if not part compute in the second code?
What I'm saying is, in the first code the i % 3 == 0 or i % 5 == 0 had to be exclusively stated whereas the same thing is achieved on the second code without the == 0.
Using De Morgan's laws:
i % 3 == 0 or i % 5 == 0
is the same as:
not (i % 3 != 0 and i % 5 != 0)
And in python, when converting a number to a boolean, any non-zero value becomes True.
So instead of doing i % 3 != 0 in the if, you can just use i % 3, because if it's 0 it'll be False and if it's non-zero it'll be True.
Here's python's truth table: https://docs.python.org/3.6/library/stdtypes.html#truth
P.S. sum() can take a generator as an argument, so you can actually just do:
sum(i for i in range(1, 1000) if not (i%3 and i%5))
and and or are boolean operators, not logical & and |. So writing
a == 0 or b == 0
is the same as writing
not a or not b
So they do the same thing
As a conclusion, the best way is to avoid negations in your conditions, don't create extra list comprehension but use generator comprehension instead, and I wouldn't mind testing against zero instead of using not since they're integers after all. I would do this:
print(sum(i for i in range(1, 1000) if i%3==0 or i%5==0))
This is an effect of the way Python converts integers to booleans. The result of i % 3 is 0, 1, or 2, depending on the value of i. In Python 3.x (and by default also in Python 2.x, unless you've reassigned them) all non-zero integers evaluate to False and zero evaluates to True.
Thus if not (i % 3) will evaluate (i % 3) to an integer 0, 1, or 2, and then not will convert these to False, True, True.
In Python 0 is usual interpreted as false. So in the first code block i % 3 == 0 is effectively equivalent to not i % 3. Examples from command line:
>>> 6 % 3 == 0
True
>>> not 6 % 3
True
>>> 7 % 3 == 0
False
>>> not 7 % 3
False
This shortcut of 0 === false appears in many languages and can be a bit confusing if you're not used to it.
In Python every object has a boolean value.
In the case of integers any of them is True except 0.
So in your case when number i can be divided by 3 the expression i % 3 will be 0. But we know that 0 is False. The not operator will negate this expression so not False will become True.
The same holds for not i % 5 as well.
Hope it helps.
Any object can be tested for truth value, for use in an if or while condition or as operand of the Boolean operations below. The following values are considered false:
None
False
zero of any numeric type, for example, 0, 0L, 0.0, 0j.
any empty sequence, for example, '', (), [].
any empty mapping, for example, {}.
instances of user-defined classes, if the class defines a nonzero() or len() method, when that method returns the integer zero or bool value False. [1]
All other values are considered true — so objects of many types are always true.
See also:
https://docs.python.org/2/library/stdtypes.html
see, i % 3 == 0 return true if the condition satisfy. Now, in python suppose:
i = 6
6 % 3 = 0 and 0==0 is true
There fore the result will be true.
In the second case
6 % 3 = 0.
Now, in boolean 0 means false. So by using not it means not false, i.e, true.
i try to write a short golf code without using letters "eiou" and i found that (a,b)[conditions] is equal to if statement, but i have no idea why it doesn't work.
a_factaral=lambda x:(a_factaral(x-1)*x,1)[x==0]
Please for some tips
bool is a subclass of int. False is 0 and True is 1.
>>> True+True
2
Logical predicates like x==0 return a boolean value.
>>> x=0
>>> x==0
True
The logical predicate can act as an index of 0 or 1. If the predicate is False, the index is 0. Otherwise, it's 1.
>>> (1, 2)[x!=0]
1
>>> (1, 2)[x==0]
2
Your function returns a_factaral(x-1)*x if x is anything other than 0, or 1 when x has reached 0 (the stopping point for the recursion).
You could ungolf this as follows:
def a_factaral(num):
if num == 0:
return 1
else:
return a_factaral(num-1) * num
(a_factaral(x-1)*x,1)[x==0] will calculate the first value first, then decide which value to take out depends on the result of x==0.
a_factaral=lambda x:((x!=0 and a_factaral(x-1)*x) or 1) will work for the same function. But in the case you cannot use 'eiou', I have no idea for alternative solution.
def name(x):
return x==('Jenson'or'Amra'or'McCay'or'Spinner'or'Jones')
print(name('Jenson'))
print(name('McCay'))
This is the question:
"Write a function that takes as input a name of a person (e.g.,
“smith”, “jones”, etc.) This function should check to see if the name
is one of the five names of people on the board. The five names are:
“Jenson”,”Amra”, “McCay”,”Spinner”, and “Jones”. If the name input
into the function is one of those five names, the function should
return the Boolean value True, and if it isn’t, the function should
return False. (remember comments with input types, description, and
test cases) Test the function to make sure it works."
It works if I am doing Jenson but it comes out with false if I put in any other name.
Try like this,
def name(x):
return x in ('Jenson', 'Amra' ,'McCay', 'Spinner','Jones')
How about the "long" way:
def check_name(x):
names_to_check = ('Jenson','Amra','McCay','Spinner','Jones')
for i in names_to_check:
if i == x:
return True
return False
Here is what is happening in your code:
x = 'Jenson', since this is what you have passed in.
This line x == ('Jenson' or 'Amra' or 'McCay' or 'Jones') is actually a boolean operation, and the result of it is always Jenson.
Boolean operations check truth values, and a non-empty string in Python is always True. So actually what ('Jenson' or 'Amra' or 'McCay' or 'Jones') is saying is:
"Either Jenson or Amra or McCay or Jones which ever one is True, set the value to that".
Since Jenson is the first item, and its True (that is, its not an empty string), the entire expression is equal to Jenson (which is why it only works when you pass in Jenson).
A simple example:
>>> ('a' or 'b' or 'c')
'a'
>>> ('b' or 'a' or 'c')
'b'
>>> ('' or '' or 'a')
'a'
>>> (0 or 0 or 1)
1
>>> (False or False or True)
True
The last three illustrate the same comparison. I am checking two empty strings and 'a'. Since an empty string is False in Python, the only thing that is "True" is 'a', which is what is returned, just as if I was comparing 0 with 1.
The syntax x==('Jenson' or 'Amra' or 'McCay' or 'Spinner'or'Jones') is wrong.
It should be like Adem says. or maybe
def name(x):
return x=='Jenson' or x== 'Amra' or x == 'McCay' or x == 'Spinner' or x == 'Jones'
I imagine what is happening is that ('Jenson'or'Amra'or'McCay'or'Spinner'or'Jones') is being evaluated first, and is evaluated to 'Jenson'. That is computed before x is even considered because it is in parentheses. Then x is checked for equality against Jenson. You need to either use a more advanced syntax like x in... as in Adem's answer, or else use return x == 'Jenson' or x == 'Amra' or x == 'McCay'... so that each comparison is run one after another.