I hope I'm missing something obvious here, but I was playing around with the Python CodingBat site, and got to the problem front_back:
For a string passed in, return it with its first and last characters swapped, if the string length is greater than 1.
I came up with a single line solution which I thought would suffice but Coding.bat refuses to accept it, with an Index out of range error.
I've played around in IDLE (64bit windows version) and I've boiled the problem down to this:
len(str) < 2 and str or 'doh ' + str + ' /doh'
The wierd problem is that setting str = '' returns:
'doh /doh'
Which it shouldn't as len('') is 0, but str='a' returns:
'a'
and str='abc' returns:
'doh abc /doh'
Which I would expect...
So my question is really; Why is checking the len of '' going to the OR condition of the ternary operator, but running len('') at the console return 0, which is obviously less than 2?
Edit:
This solution actually works, however:
def front_back(str):
if len(str) < 2:
return str
else:
return str[-1] + str[1:-1] + str[0]
To 'mtadd'; thanks for your answer but this isn't a logical and/or this is a pythonic ternary operator:
return (statement) and <statement was true> or <statement was false>
It's the same as C#'s:
return statement
? trueValue
: falseValue;
Its a matter of operator precedence.
In the case of your expressions, the implicit ordering is as follows
((len(str) < 2) and str) or ('doh ' + str + ' /doh')
In the case of str = "", len(str) < 2 evaluates True, but str, an empty string, evaluates to False, thus the and expression is False, so the right operand of the or binary op becomes the result of the expression.
For the case of str = "abc", len(str) < 2 is False, so the and expression short-circuits as False, and the expression to the right of the or is the result.
For the case of str = "ab", len(str) < 2 is True, so the and expression passes its right operand to the or binary operator, and since bool("ab") == True, the value of str becomes the result of the expression.
As you can see, using and/or will not work similarly to other language's ternary operators if your result in the case of a True condition is equivalent to False, e.g.
True and 0 or 1 yields 1, whereas using 0 if True else 1 yields 0.
I'd recommend using python's ternary if/else expression, e.g.:
str if len(str) < 2 else 'doh ' + str + ' /doh'
def front_times(str, n):
return str[0:3] * n
Related
This question already has answers here:
How do "and" and "or" act with non-boolean values?
(8 answers)
Closed 1 year ago.
Recently I read several lines of Python codes and got a bit confused.
p = 'a*b.*'
lp = len(p)
m = [0]*(lp+1)
for i in range(1, lp + 1):
m[i] = m[i-1] and p[i-1] == '*' or (i > 1 and m[i-2] and p[i-1] == '*')
print(m)
The result printed out as [0, False, 0, False, 0, False]
p is a string, and lp is the length of string p. I created a list m [0, 0, 0, 0, 0, 0]. Then I am getting confused:
I loop all the elements in this array(list). What does "and" and "or" mean here in the loop. Double equal signs are also used here. I thought "and" and "or" can only be used under if-else clauses. What does this mean here? Could anyone please translate for me? Thanks!
and and or are actually boolean operators and they can be used anywhere to compare two values.
According to the docs,
The expression x and y first evaluates x; if x is false, its value is returned; otherwise, y is evaluated and the resulting value is returned.
The expression x or y first evaluates x; if x is true, its value is returned; otherwise, y is evaluated and the resulting value is returned.
Note also that
In the context of Boolean operations, and also when expressions are used by control flow statements, the following values are interpreted as false: False, None, numeric zero of all types, and empty strings and containers (including strings, tuples, lists, dictionaries, sets and frozensets). All other values are interpreted as true.
So, in your case, the values being compared are
m[i-1] type int, evaluates to False if it's 0 else True
p[i-1] == '*' type bool, evaluates to False if p[i-1] is not equal to '*' else True
i > 1 type bool, evalueates to False if i is less or equal to 1 else True
m[i-2] type int, evaluates to False if it's 0 else True
So why the snippet outputs [0, False, 0, False, 0, False]? If you debug this program, you'll notice that in some iterations, the value at the left of the first and is returned. In these iterations, the result will be a integer (0) since m[i-1] is a integer. In other iterations, the value at the right of the first and is returned. In these, the result will be a boolean.
def string_to_int_list(s):
L1=[]
for i in s.split(','):
if i:#what does this line mean?
L1.append(int(i))
return L1
I want to convert string to list,and if I delete 'if i',it will remind me that ValueError: invalid literal for int() with base 10: ''
if i has a value, the condition will return true, if the value of i is None (empty), it will return false. It's the same as i != None.
Also I test that if the split function returns an empty string "" it will not pass the if condition.
For check if a string is numeric (0 - 9) you can use str.isdigit()
str.isdigit()
Return true if all characters in the string are digits and there is at least one character, false otherwise.
For 8-bit strings, this method is locale-dependent.
This code works:
def string_to_int_list(s):
L1=[]
for i in s.split(','):
if i and i.isdigit():#what does this line mean?
L1.append(int(i))
return L1
a = "1,2,3,q,43,hello"
b = string_to_int_list(a)
print b
It will return [1, 2, 3, 43]
Note that I remove indentation to return because it has no sense inside the loop.
What you are doing here is splitting your string by , and then converting to integer if you see a valid value.
Let's say your 1,2,3,4,,,5
What the script is returning you a list of [1,2,3,4,5]
You should try what if condition returns for a empty string, None, empty list i.e. [] or {}.
This script will fail if you have "abc,2,3,4,5"
You can also functional loops like
filter(lambda x : x , map(lambda x : int(x) if x else None, a.split(",")))
First off, this IS homework, so I am not expecting any direct answers. I need to take two strings defined by a function (semordnilap(str1, str2)) and I need to see if they are equal when one is reversed. I was wondering if I can call these separately out of the function with semordnilap(str1[0:1) == semordnilap(str2[-1]) I tried this a few ways and I must not be thinking about it correctly, plus of course there is the kicker of trying to do this recursively. Any advise or direction would be helpful.
def semordnilap(str1, str2):
'''
str1: a string
str2: a string
returns: True if str1 and str2 are semordnilap
False otherwise.
'''
if len(str1) != len(str2):
return False
if len(str1) <= 1 or len(str2) <= 1:
return False
if semordnilap(str1[0]) != semordnilap(str2[-1]):
return False
else:
return True
This is what I have so far, getting error of TypeError: semordnilap() takes exactly 2 arguments (1 given)
Given two strings str1 and str2, the easiest way to compare if one is equal to the reverse of the other is by using slicing:
str1 = 'racecar'
str2 = 'racecar'
str1 == str2[::-1]
Out[57]: True
Which is really just checking if str1 is a palindrome (i.e. a reverse of itself).
If you really want to use recursion, you also want to be using slicing: check if str1[0] == str2[-1], and then recursively call your function on str1[1:] and str2[:-1].
The [::-1] syntax is extended slicing syntax, which is valid for strings as well as lists and other sequences.
To reverse a string you use 'this is a string'[::-1].
[::-1] Is slice notation which says include everything from the start to the end of the string but do it in reverse.
'abcdefghijk'[6:1:-2] outputs 'gec' because it goes from the 6th index (starting with 0) up to but not including the first index, in reverse steps of 2.
Read up more on slice notation:Explain Python's slice notation, http://docs.python.org/2.3/whatsnew/section-slices.html
def semordnilap(str1, str2):
if str1 == str2[::-1]: return True
else: return False
One way to do it recursively:
def semordnilap(str1, str2):
if not (len(str1) or len(str2)): return True
if not (len(str1) and len(str2)): return False
if str1[0] != str2[-1]: return False
return semordnilap(str1[1:], str2[:-1])
The first line checks if both strings are empty (0 evaluates to False, any other number is True). len(str1) returns the length as an integer.
Then it checks if only one of the strings is empty in which case they are not equal.
Then it checks if the first letter is the same as the last letter.
Then it repeats the process with the each string (minus the first letter of str1 and minus the last letter of str2). It goes until one of the base cases is reached. The base case is what is returned. So it will only return True when then first letter was equal to the last letter each round until both strings ran out of characters at the same time.
>>> 20130708 < ''
True
>>> 20130708 > ''
False
I am not sure what the explanation for this is. The wikipedia article on lexicographical ordering says that
u < v if u is a prefix of v
Since "" is a prefix of "20130708", I would expect "20130708" < "" to be false.
Your question title doesn't match your code. You're not comparing "20130708" with "", you're comparing 20130708 with "" - ie an integer, with an empty string.
It's a peculiarity of Python 2 that integers always compare less than strings. In Python 3, this is fixed, and that code raises TypeError: unorderable types: int() < str().
You are missing quotes here:
>>> "20130708" < ""
False
What you are doing is comparing ints to str, which are rich comparisons. So any int is "smaller" than any str.
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.