I have discovered something in python today. But haven't found a clear explanation for it yet.
In python it seems that this works:
variable += a_single_statement
So, following statements are correct:
variable += another_variable
variable += (another_variable - something_else)
But doing the following is incorrect:
variable += a_variable - b_variable
Could someone explain why this is the case, preferably with a link to the documentation to the syntactical structure that explains what the operands of a += operator are, what expressions are expected and what their structure is? Also, are my thoughts, outlined above, even correct?
The behavior seems to be different from other programming languages I'm used too, and that last 'statement' leads to a syntax error.
Edit: the code where it doesn't work. It might be a whitespace error instead :/
T = input()
counter = 0
# For each word, figure out edit length to palindrome
for _ in range(T):
counter += 1
word = raw_input()
word_len = len(word) #stored for efficiency
index = 0
sum_edits = 0
# Iterate half the word and always compare characters
# at equal distance d from the beginning and from
# the ending of the word
while index < word_len/2.0:
sum_edits += max(ord(word[index]), ord(word[word_len-index-1])) -
min(ord(word[index]), ord(word[word_len - index - 1]))
index += 1
print sum_edits
It's code to detect how many edits it would take to make a word into a palindrome, if you could only change letters 'downwards' towards an 'a'.
Does this mean you can not arbitrarily break up a line in python code, if it's clear that the 'expression' has to continue anyway? Or can you only break up lines of code if they are surrounded with parentheses?
Sorry, I'm very new to python.
It has nothing to do with +=. It's just that Python doesn't let you split a statement across multiple lines unless there's an open (, {, or [, or unless you perform a line continuation with \. It might look obvious that those two lines are supposed to be one statement, but then when you have statements like
a = loooooooooooooooooooooooooooooong_thiiiiiiiiiiiiiiiiiiiiiiiing
+ ooooooooooooootheeeeeeeeeeeeer_thiiiiiiiiiiiiiiiiiiiing
is that one statement or two? If you allow
a = loooooooooooooooooooooooooooooong_thiiiiiiiiiiiiiiiiiiiiiiiing +
ooooooooooooootheeeeeeeeeeeeer_thiiiiiiiiiiiiiiiiiiiing
to be one statement, then either interpretation for having the + operator on the second line is confusing and bug-prone. Javascript tries to allow this kind of thing, and its semicolon insertion causes all kinds of problems.
It's usually recommended to use parentheses if you're not already inside brackets or braces.
Related
I am learning how to code. I need to code, among other things, an adaptor removal tool. My scripts works fine except in the cases where the sequence is a mix of lower and upper cases.
adaptor sequence== TATA
sequence == TAtaGATTACA
This is the function for the adaptor removal
elif operation == "adaptor-removal":
adaptor = args.adaptor
reads = sequences(args.input, format)
num_reads = len(reads)
bases = "".join([read["seq"] for read in reads])
adaptors_found = 0
for read in reads:
for i, j in read.items():
if i == "seq":
if j.startswith(adaptor.upper()) or j.startswith(adaptor.lower()):
adaptors_found += 1
j = j.replace(adaptor.upper(), "", 1)
j = j.replace(adaptor.lower(), "", 1)
args.output.write("%s\n" % j)
print_summary(operation)
print("%s adaptors found" % adaptors_found)
I tried with:
if j.startswith(adaptor,re.I):
but doesn't work, I don't really understand why. Can anyone experienced guide me through this?
Thank you very much
Let's suppose j is TAtaGATTACA and adaptor is TATA.
Is j.startswith(adaptor.upper()) true? No, because j doesn't start with TATA.
Is j.startswith(adaptor.lower()) true? No, because j doesn't start with tata.
The easiest way to compare two strings case-insensitively is to convert both of them to the same case, upper or lower, and then compare those two strings as if you were comparing them case-sensitively. It doesn't matter whether you choose upper-case or lower-case, as long as you choose the same for both.
Is j.lower().startswith(adaptor.lower()) true? Yes, because j.lower() starts with tata.
Also, take care with your two .replace() calls: it's possible that one of them may end up removing text further along in j, which I don't believe you want. If you just want to trim the adaptor off the front of j, you are better off using a string slice:
if j.lower().startswith(adaptor.lower()):
adaptors_found += 1
j = j[len(adaptor):]
Finally, you also ask why
if j.startswith(adaptor,re.I):
doesn't do what you want. The answer is that if you pass a second parameter to .startswith(), the value of this second parameter is the start position that you search from, not a flag that controls the matching:
"abcd".startswith("cd") # False
"abcd".startswith("cd", 2) # True
It happens that re.I can be converted to the integer 2. So the following is also True, although it looks odd:
"abcd".startswith("cd", re.I)
I have the following function that generates the longest palindrome of a string by removing and re-ordering the characters:
from collections import Counter
def find_longest_palindrome(s):
count = Counter(s)
chars = list(set(s))
beg, mid, end = '', '', ''
for i in range(len(chars)):
if count[chars[i]] % 2 != 0:
mid = chars[i]
count[chars[i - 1]] -= 1
else:
for j in range(0, int(count[chars[i]] / 2)):
beg += chars[i]
end = beg
end = ''.join(list(reversed(end)))
return beg + mid + end
out = find_longest_palindrome('aacggg')
print(out)
I got this function by 'translating' this example from C++
When ever I run my function, I get one of the following outputs at random it seems:
a
aca
agcga
The correct one in this case is 'agcga' as this is the longest palindrome for the input string 'aacggg'.
Could anyone suggest why this is occurring and how I could get the function to reliably return the longest palindrome?
P.S. The C++ code does not have this issue.
Your code depends on the order of list(set(s)).
But sets are unordered.
In CPython 3.4-3.7, the specific order you happen to get for sets of strings depends on the hash values for strings, which are explicitly randomized at startup, so it makes sense that you’d get different results on each run.
The reason you don’t see this in C++ is that the C++ set class template is not an unordered set, but a sorted set (based on a binary search tree, instead of a hash table), so you always get the same order in every run.
You could get the same behavior in Python by calling sorted on the set instead of just copying it to a list in whatever order it has.
But the code still isn’t correct; it just happens to work for some examples because the sorted order happens to give you the characters in most-repeated order. But that’s obviously not true in general, so you need to rethink your logic.
The most obvious difference introduced in your translation is this:
count[ch--]--;
… or, since you're looping over the characters by index instead of directly, more like:
count[chars[i--]]--;
Either way, this decrements the count of the current character, and then decrements the current character so that the loop will re-check the same character the next time through. You've turned this into something completely different:
count[chars[i - 1]] -= 1
This just decrements the count of the previous character.
In a for-each loop, you can't just change the loop variable and have any effect on the looping. To exactly replicate the C++ behavior, you'd either need to switch to a while loop, or put a while True: loop inside the for loop to get the same "repeat the same character" effect.
And, of course, you have to decrement the count of the current character, not decrement the count of the previous character that you're never going to see again.
for i in range(len(chars)):
while True:
if count[chars[i]] % 2 != 0:
mid = chars[i]
count[chars[i]] -= 1
else:
for j in range(0, int(count[chars[i]] / 2)):
beg += chars[i]
break
Of course you could obviously simplify this—starting with just looping for ch in chars:, but if you think about the logic of how the two loops work together, you should be able to see how to remove a whole level of indentation here. But this seems to be the smallest change to your code.
Notice that if you do this change, without the sorted change, the answer is chosen randomly when the correct answer is ambiguous—e.g., your example will give agcga one time, then aggga the next time.
Adding the sorted will make that choice consistent, but no less arbitrary.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
Im a beginner to your world. I have seen many attempts to answer this question using fancy builtin function and have found the answer on how to do this a thousand times but NONE using two for loops method.
I would like for the code to only reverse a vowel when it finds one in a string, using the two for loop method.
I coded something that didnt seem to work and I dont quite understand why,
for x in newWord:
for y in vowels:
if x == y:
newWord[x] = newWord[7]
print newWord
with vowels being a list of vowels, with newWord also being a list.
This code is currently not working, like most others who have tried the two for loop method. Any help is appreciated. Thanks
Roughly the approach you want to use is to make two passes over the list of characters. In the first pass you find the index of each vowel, building a list of work to be done (locations of vowels to be swapped).
Then you prepare your work list by matching the first and last items until you have less than two items left in the work list. (An odd number of vowels means that the one in the middle doesn't have to be swapped with anything).
Now you simply iterate over the work list, tuples/pairs of indexes. Swap the character at the first offset with the character at the other one for each pair. Done.
(This is assuming you want transform the list in place. If not then you can either just start with a copy: new_word = word[:] or can iterate over enumerate(word) and conditionally either append the character at each point (if the offset isn't in your work list) ... or append the offset character (if this index matches one of those in your list). I the latter case you might make your work list a dictionary instead).
Here's the code to demonstrate:
def rev_vowels(word):
word = list(word)
results = word[:]
vowel_locations = [index for index, char in enumerate(word) if char in 'aeiou']
work = zip(vowel_locations[:int(len(vowel_locations)/2)], reversed(vowel_locations))
for left, right in work:
results[left], results[right] = word[right], word[left]
return results
This does use a list comprehension, the zip() and reversed() builtins, a complex slice for the first argument to zip(), and the Python tuple packing idiom for swapping variables. So you might have to replace those with more verbose constructs to fulfill your "no fancy builtins" constraint.
Fundamentally, however, a list comprehension is just syntactic sugar around a for loop. So, overall, this demonstrates the approach using two for loops over the data. While I'm returning a copy of the data as my results the code would work without that. (That's why I'm using the tuple packing idiom on line seven (just before the return statement).
If this question is being asked in an interview context I'm reasonably confident that this would be a reasonably good answer. You can easily break down how to implement zip, how to expand a list comprehension into a traditional for suite (block), and the swap line could be two separate assignments when returning a copy rather than performing an in-place transformation on the data.
These variable names are very verbose. But that's to make the intentions especially clear.
This code should solve your problem without using any "fancy builtin functions".
def f(word):
vowels = "aeiou"
string = list(word)
i = 0
j = len(word)-1
while i < j:
if string[i].lower() not in vowels:
i += 1
elif string[j].lower() not in vowels:
j -= 1
else:
string[i], string[j] = string[j], string[i]
i += 1
j -= 1
return "".join(string)
Pardon the incredibly trivial/noob question, at least it should be easy to answer. I've been working through the coderbyte problems and solving the easy ones in python, but have come across a wall. the problem is to return True if a string (e.g. d+==f+d++) has all alpha characters surrounded by plus signs (+) and if not return false. I'm blanking on the concept that would help navigate around these strings, I tried doing with a loop and if statement, but it failed to loop through the text entirely, and always returned false (from the first problem):
def SimpleSymbols(str):
split = list(str)
rawletters = "abcdefghijklmnopqrstuvwxyz"
letters = list(rawletters)
for i in split:
if i in letters and (((split.index(i)) - 1) == '+') and (((split.index(i)) + 1) == '+'):
return True
else:
return False
print SimpleSymbols(raw_input())
Also editing to add the problem statement: "Using the Python language, have the function SimpleSymbols(str) take the str parameter being passed and determine if it is an acceptable sequence by either returning the string true or false. The str parameter will be composed of + and = symbols with several letters between them (ie. ++d+===+c++==a) and for the string to be true each letter must be surrounded by a + symbol. So the string to the left would be false. The string will not be empty and will have at least one letter."
Any assistance would be greatly appreciated. Thank you!
Here's how I would do the first part (if I weren't using regex):
import string
LOWERCASE = set(string.ascii_lowercase)
def plus_surrounds(s):
"""Return True if `+` surrounds a single ascii lowercase letter."""
# initialize to 0 -- The first time through the loop is guaranteed not
# to find anything, but it will initialize `idx1` and `idx2` for us.
# We could actually make this more efficient by factoring out
# the first 2 `find` operations (left as an exercise).
idx2 = idx1 = 0
# if the indices are negative, we hit the end of the string.
while idx2 >= 0 and idx1 >= 0:
# if they're 2 spaces apart, check the character between them
# otherwise, keep going.
if (idx2 - idx1 == 2) and (s[idx1+1] in LOWERCASE):
return True
idx1 = s.find('+', idx2)
idx2 = s.find('+', max(idx1+1, 0))
return False
assert plus_surrounds('s+s+s')
assert plus_surrounds('+s+')
assert not plus_surrounds('+aa+')
I think that if you study this code and understand it, you should be able to get the second part without too much trouble.
More of a note than an answer, but I wanted to mention regular expressions as a solution not because it's the right one for your scenario (this looks distinctly homework-ish so I understand you're almost certainly not allowed to use regex) but just to ingrain upon you early that in Python, almost EVERYTHING is solved by import foo.
import re
def SimpleSymbols(target):
return not (re.search(r"[^a-zA-Z+=]",target) and re.search(r"(?<!\+)\w|\w(?!\+)",target))
This is my first effort on solving the exercise. I gotta say, I'm kind of liking Python. :D
# D. verbing
# Given a string, if its length is at least 3,
# add 'ing' to its end.
# Unless it already ends in 'ing', in which case
# add 'ly' instead.
# If the string length is less than 3, leave it unchanged.
# Return the resulting string.
def verbing(s):
if len(s) >= 3:
if s[-3:] == "ing":
s += "ly"
else:
s += "ing"
return s
else:
return s
# +++your code here+++
return
What do you think I could improve on here?
def verbing(s):
if len(s) >= 3:
if s.endswith("ing"):
s += "ly"
else:
s += "ing"
return s
How about this little rewrite:
def verbing(s):
if len(s) < 3:
return s
elif s.endswith('ing'):
return s + 'ly'
else:
return s + 'ing'
I would use s.endswith("ing") in the if, which is also a bit faster, because it doesn't create a new string for the comparision.
And second, I would use docstrings for commenting. This way, you can see your description when you do a help(yourmodule) or when you use some autodoc-tool like Sphinx to create a handbook describing your API. Example:
def verbings(s):
"""Given a string, if its length is at least 3, add 'ing' to its end.
Unless it already ends in 'ing', in which case add 'ly' instead.
If the string length is less than 3, leave it unchanged."""
# rest of the function
Third, it's often considered a bad practice to change input parameters. You can do it for dict or list parameters, which can also act as output parameters. But strings are input parameters only (that's why you have the return). The source you have written is valid of course, but is often confusing. Other languages have often a final or const keyword to avoid this confusion, but Python doesn't. So, I would recommend you, to use either a second variable result = s + "ing" and do a return result afterwards, or write return s + "ing".
The rest is perfectly fine. There are of course some constructs in Python which are shorter to write (you will learn them with the time), but they are often not so readable. Therefore I would stay with your solution.
Pretty good for a beginner! Yes, I would say this is the Pythonic way of doing things. I especially like the way you have commented exactly what the function does. Good work there.
Keep working with Python, though. You're doing fine.
def add_string(str1):
if(len(str1)>=3):
if (str1[-3::] == 'ing'):
str1+='ly'
else:
str1+='ing'
return str1
str1="com"
print(add_string(str1))