Related
I was wondering how to take advantage of shorthand notation of if-else and += in Python of this simple expression:
I tried to set brackets everywhere and changed += to *= which didn't change the situation of course.
This works as expected:
a, b = 0, True
for i in range(123):
if b == True:
a = a + 1
Still working as expected, trying shorthand of if-else led me to:
a, b = 0, True
for i in range(123):
a = a + 1 if b == True else a
Finally the attempt to write:
a, b = 0, True
for i in range(123):
a += 1 if b == True else a:
fails and surprisingly I get pretty quickly huge integers for a
Moreover I'd really like something more shorthanded, e.g.:
a, b = 0, True
for i in range(123):
a += 1 if b
The for-loop needs to stay as it is, since in my case there are other operations that affect b.
Since noone seems to be posting, why it goes like this, here is mine - lines:
a = a + 1 if b == True else a
a += 1 if b == True else a
are seen by python as:
a = (a + 1 if b == True else a)
a += (1 if b == True else a)
This is why you get large numbers fast in second version - you will add a to a, when b is False. If you want to keep the if, then go:
a += (1 if b else 0)
Also don't compare b to True (or False), go foif b`, as it's more pythonic (it will prevent some weird mistakes, when other code will start to interact with yours).
EDIT: go for #Tomerikoo answer for even shorter code, but keep in mind, that those waters can be muddy and not everyone knows / easily follows, that adding boolean to int treats first as 1 (or 0 if False).
To closest to your proal is probably:
a, b = 0, True
for i in range(123):
a += b
Since bool is a subtype of int, no conversion is necessary.
You can do:
for i in range(123):
if b:a+=1
You can also do:
for i in range(123):
a = a + 1*b
Because booleans are ints:
>>> isinstance(True, int)
True
>>> True == 1
True
just note that
a += x if condition else y
will resolve to a += x if the condition is True; otherwise it will be a += y. this is why your numbers get big...
apart from that i suggest you use what U10-Forward's answer suggests.
The in operator tests for equivalence using comparison, but Python's comparison isn't precise in the sense that True == 1 and 0 == False, yielding -
>>> True in [ 1 ]
True
>>> False in [ 0 ]
True
>>> 1 in [ True ]
True
>>> 0 in [ False ]
True
whereas I need a precise comparison (similar to === in other languages) that would yield False in all of the above examples. I could of course iterate over the list:
res = False
for member in mylist:
if subject == member and type( subject ) == type( member ):
res = True
break
This is obviously much less efficient then using the builtin in operator, even if I pack it as a list comprehension. Is there some native alternative to in such as a list method or some way to tweak in's behavior to get the required result?
The in operator is used in my case for testing the uniqueness of all list members, so a native uniqueness test would do as well.
Important note: The list may contain mutable values, so using set isn't an option.
Python version is 3.4, would be great for the solution to work on 2.7 too.
EDIT TO ALL THOSE WHO SUGGEST USING IS:
I look for a non-iterating, native alternative to a in b.
The is operator is not relevant for this case. For example, in the following situation in works just fine but is won't:
>>> [1,2] in [[1,2]]
True
Please, do read the question before answering it...
in doesn't test for equivalence at all. It checks if an item is in a container. Example:
>>> 5 in [1,2,3,4,5]
True
>>> 6 in [1,2,3,4,5]
False
>>> True in {True, False}
True
>>> "k" in ("b","c")
True
What you are looking for is is.
>>> True == 1
True
>>> True is 1
False
>>> False == 0
True
>>> False is 0
False
EDIT
After reading your edit, I don't think there is something built in in python libraries that suits your needs. What you want is basically to differentiate between int and bool (True, False). But python itself treats True and False as integers. This is because bool is a subclass of int. Which is why True == 1 and False==0 evaluates to true. You can even do:
>>> isinstance ( True, int)
True
I cannot think of anything better than your own solution, However, if your list is certain to contain any item not more than once you can use list.index()
try:
index_val = mylist.index(subject)
except ValueError:
index_val = None
if (index_val!=None):
return type(subject) == type(member)
Since index is built-in, it might be a little faster, though rather inelegant.
Python in operator is precise and the behavior you're complaining of is perfectly expected, since bool is a subclass of int.
Below is the excerpt of the official Python documentation describing the boolean type:
Booleans
These represent the truth values False and True. The two objects representing the values False and True are the only Boolean objects. The Boolean type is a subtype of plain integers, and Boolean values behave like the values 0 and 1, respectively, in almost all contexts, the exception being that when converted to a string, the strings "False" or "True" are returned, respectively.
You can also have a look at PEP 285.
You're looking for the is operator:
if any(x is True for x in l):
...
is, however, isn't exactly === from other languages. is checks identity, not just equality without type coercion. Since CPython uses string and integer interning, two objects that are equal may not be the same object:
In [19]: a = '12'
In [20]: b = '123'
In [21]: a += '3'
In [22]: a is b
Out[22]: False
In [23]: a == b
Out[23]: True
In [27]: 100001 is 100000 + 1
Out[27]: False
In [28]: 100001 == 100000 + 1
Out[28]: True
In Python 3, None, True, and False are essentially singletons, so using is for discerning True from 1 will work perfectly fine. In Python 2, however, this is possible:
In [29]: True = 1
In [31]: True is 1
Out[31]: True
Equality can be overridden __eq__ method, so you can define an object that is equal to any other object:
In [1]: %paste
class Test(object):
def __eq__(self, other):
return True
## -- End pasted text --
In [2]: x = Test()
In [3]: x == None
Out[3]: True
In [4]: x == True
Out[4]: True
In [5]: x == False
Out[5]: True
In this case, how would === work? There is no general solution, so Python has no built-in method of lists that does what you want.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Right now I'm trying to use recursion of a function with two parameters to find whether or not the second is included in the first. As an example:
def recurseString(full, inclusive):
...............
With this I would take something along the lines of:
recurseString('jack','kcj')
and this would return "True" whereas something like:
recurseString('stan','xun')
would return "False"
I'm rather new to python so this is rather confusing. Any ideas on how to go about this problem?
I am guessing that you are looking for ...
In [51]: def recurseString(a,b):
....: if b == '': return True
....: else:
....: if len(b) == 1: return b in a
....: else: return (b[0] in a) and recurseString(a, b[1:])
....:
In [52]: recurseString('jack', 'kjc')
Out[52]: True
In [53]: recurseString('stan', 'xun')
Out[53]: False
However, there is no need for recursion. This is much better solved using all like so:
In [57]: all( [s in 'jack' for s in 'kjc'] )
Out[57]: True
which is far more Pythonic.
It is also possible to use reduce which is more functional but much less readable, since Python has much better ways of handling this.
In [60]: reduce(lambda x,y: (x and (y in 'jack')) , 'kjc', True)
Out[60]: True
Finally, this wouldn't be complete without using the set notation:
In [65]: (set('kjc') - set('jack')) == set()
Out[65]: True
So as you can see, the recursive version is the least suitable for this problem!
This will return True even if there are duplicate letters in inclusive but but only one in full:
def recurseString(full, inclusive):
if not inclusive:
return True
return inclusive[0] in full and recurseString(full, inclusive[1:])
>>> print recurseString('jack','kkkcccjjj')
True
The following requires full to contain the same number of duplicate letters - if inclusive has three k's full must have three k's:
def recurseString(full, inclusive, first_call = True):
# first time through, sort the arguments to make the algorithm easier
if first_call:
full, inclusive = map(sorted, (full, inclusive))
first_call = False
# two base cases, inclusive has been exhausted
if not inclusive:
return True
try:
index = full.index(inclusive[0])
except ValueError:
# and (2nd base case) first item of inclusive is not in full
return False
return recurseString(full[index+1:], inclusive[1:], first_call)
>>> print recurseString('jack','kkkcccjjj')
False
>>> print recurseString('jckackjkjc','kkkcccjjj')
True
>>>
Using the index method seemed like cheating -
def foo(full, inclusive, first_call = True):
if first_call:
full, inclusive = map(sorted, (full, inclusive))
if not full and inclusive:
return False
if not inclusive:
return True
if inclusive[0] == full[0]:
inclusive = inclusive[1:]
return foo(full[1:], inclusive, False)
assert not foo('','kkkcccjjj')
assert not foo('sun','xun')
assert not foo('jack','kkkcccjjj')
assert foo('s', 's')
assert foo('jckackjkjc','kkkcccjjj')
assert foo('','')
assert foo('a','')
To think about any problem recursively, you have to break it into a base case (or sometimes multiple base cases), and a recursive case (or sometimes multiple recursive cases).
I'm going to assume that "included by" means "each character in inclusive is also in full, and in fact each character that appears in inclusive N times is also in full at least N times".
So, if inclusive is empty, it's vacuously True.
But if the full is empty and inclusive is not, it's False.
Otherwise, if the first character of full is in inclusive, it's true iff full[1:] contains inclusive minus that character.
Otherwise, it's true iff full[1:] contains inclusive.
Now you just have to translate that to code.
If you don't need to handle repeated characters, you can simplify this by just testing inclusive[0] and recursing on inclusive[1:], instead of recursing on full[1:].
def recurseString(str1,str2):
if str2 == "": # str2 == "" all str2 letters are in str1
return True
elif str2[0] in str1:
return recurseString(str1, str2[1:]) # move to next letter in str2
return False # if we get here we have found a letter that is not in str1
In [22]: recurseString('stan','xun')
Out[22]: False
In [23]: recurseString('jack','kcj')
Out[23]: True
I don't know why you need recursive to implement it, it's difficult to read and understand.
MY GOD, It's a challenge for me to read my code.
def recurseSring(full, inclusive):
for i in range(len(full)):
for j in range(len(inclusive)):
if full[i] == inclusive[j]:
if recurseSring(full[i + 1:], inclusive[j + 1:]):
return True
if full[i] == inclusive[j] and len(inclusive) == 1:
return True
return False
if __name__ == "__main__":
if recurseSring('lifenglifeng001', 'lifeng'):
print('OK, equal')
else:
print('NOT equal')
Short but sweet.
def recurseString(full, incl):
return incl[:1] in full and (incl[:1] == '' or recurseString(full, incl[1:]))
The 'and' ensures both parts of the expression are true.
The first part - takes the first character of inclusive and searches for it in the full string:
incl[:1] in full #returns '' if incl is ''
The second part - this is true if you search with a null string (incl), have come to the end of incl OR if the recursive call is true called with the tail of incl used as the second arg:
incl[:1] == '' or recurseString(full, incl[1:])
#null check is first to prevent overflow
There's a simple approach for this without recursion: create two sets with the strings you want and check if one set is inside the other one.
def contains(text, chars):
textset = set(text)
charset = set(chars)
return charset.issubset(textset)
print contains("jackie", "ice") # True
print contains('jack','kcj') # True
print contains('stan','xun') # False
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.
If:
x = 0
b = x==0
and I print b it would print 'true'
but if I did:
x = 0
b = x ==3
and I printed b it would be false.
Instead of it printing false how would I take the boolean value b to print what text I wanted?
Let me explain further:
bool = all(n > 0 for n in list)
if bool != 'True':
print 'a value is not greater than zero'
But it prints nothing?
Something like this you mean?
x = 0
if x != 3:
print "x does not equal 3"
I think perhaps the following will help alleviate some of your confusion:
>>> 0==0
True
>>> 'True'
'True'
>>> (0==0) == 'True'
False
>>> (0==0) == True
True
An if statement as other answers suggest is a possibility (and you could add an else clause to print something specific in each case). More direct is an if/else operator:
print('equality' if b else 'diversity')
You could also use indexing, since False has the int value 0 and True the int value 1:
print(['different', 'the same'][b])
but I find that a bit less readable than the if variants.
Remove the quotes around True:
bool = all(n > 0 for n in list)
if bool != True:
print 'a value is not greater than zero'
or, you can also check for False:
bool = all(n > 0 for n in list)
if bool == False:
print 'a value is not greater than zero'
There are several other "shortcut" ways of writing it, but since you're a beginner let's not confuse the subject more than necessary.
>>> x = 0
>>> if not x == 3: print 'x does not equal 3'
x does not equal 3
lte me explain further:
>>> list = [-1, 1, 2, 3]
>>> if not all(n > 0 for n in list): print 'a value is not greater than zero'
a value is not greater than zero
# => or shorter ...
>>> if min(list) < 0: print 'a value is not greater than zero'
a value is not greater than zero
note that list is a builtin and shouldn't be used as a variable name.
>>> list
<type 'list'>
>>> list = [1, 2, "value not greater than 0"]
>>> list
[1, 2, "value not greater than 0"]
>>> del list
>>> list
<type 'list'>
...
a = lambda b :("not true","true")[b == 3]
print a(3)
will do it for you if you want to put it in a lambda.
You will need to do the printing yourself, as everyone suggested here.
It's worthy to note that some languages (e.g. Scala, Ruby, Groovy) have language features that enable you to write:
x should be(3)
And that will report:
0 should be 3 but is not.
In Groovy, with Spock testing framework, you can write:
def "my test":
when: x = 0
expect: x == 3
And that would output:
Condition not satisfied:
x == 3
| | |
0 | 3
false
I don't think this possibly cleanly in python though.
>>> 'True' is not True
True
'True' is a string
True is a boolean
They have nothing to do with each other, except coincidentally. The string value happens to have the same letters as the boolean literal. But that's just a coincidence.