Python recursive function that retain variable values - python

I am brushing up a bit of good old algorithms, and doing it with python, since I use it more often nowadays.
I am facing an issue when running a recursive function; where the variable get reset every time that the recursive function call itself:
def recursive_me(mystring):
chars = len(mystring)
if chars is 0:
print("Done")
else:
first = int(str[0])
total = + first
print(total)
recursive_me(mystring[1:])
recursive_me("4567")
What I am doing here is to get a string made of digits; take the first, convert it to an int; and run recursively the function again, so I can take one digit at time from the string and sum all the values.
Ideally the output should show the total, while it add all the digits (4+5+6+7), although when the recursive function is called the first time, the function reset the total value.
Is common habit to use global variables when running operations with recursive functions or am I doing something wrong?

You can code as simply as this:
def recursive_me(mystring):
if mystring: # recursive case
return int(mystring[0]) + recursive_me(mystring[1:])
else: # base case
return 0
or
def recursive_me(mystring, total = 0):
if mystring: # recursive case
return recursive_me(mystring[1:], total + int(mystring[0]))
else: # base case
return total
although this won't help much in Python since it doesn't implement tail-call optimisation.
If you want to see the intermediate values, change the second version like so:
def recursive_me(mystring, total = 0):
if mystring: # recursive case
newtotal = total + int(mystring[0])
print(newtotal)
return recursive_me(mystring[1:], newtotal)
else: # base case
return total
then
4
9
15
22
22 # this is the return value; previous output is from `print()`

as a foreword: a lot of answers received meaningful edits in the meantime I was writing this answer. Don't hold it against me.
I'm throwing my two cents in here just because there's a lot of over-complicated answers.
This is a corrected copy-paste of the OP's effort.
def recursive_me(mystring, total=0):
chars = len(mystring)
if chars is 0:
print("Done")
return total
else:
first = int(mystring[0])
total += first
print(total)
recursive_me(mystring[1:], total)
first what happens is that we check the base case, if there's no left chars in the string. If the string length is 0 we return the total calculated ammount.
Otherwise, we turn the first of the chars into an int, and add it to total. The first error you have is that you wrote str[0]. str is a python built in type and the produced error would be something like "str is not subscriptable".
This error means that the str can't be operated on by "[]" operator. The same would happen if you tried doing 1[0] because 1 is a integer. The "[]" operator can only operate on lists, tuples and strings (I might've forgot some built-in type).
The second error you had was with the addition part. You had written total = + first but the operator you are looking for is the += which in fact is just a shortened way to write a = a+b.
Additionally, your original question was concerning about "python" forgetting the value of "total". This is because you have to either pass that value forward, or write your recursive function in a way that "forces" it to, what's called, evaluate your next call to your function on the spot.
In my example I'm sending the next call of the function recursive_me, the current total value. In the example given by #uselpa; above he's making python evaluate the next call to the function by putting it after operator +:
return int(mystring[0]) + recursive_me(mystring[1:])
this then gets to be (for recursive_me("4567"))
return int(4)+recursive_me("567")
return int(4)+int(5)+recursive_me("67")
....
return int(4)+int(5)+int(6)+int(7)+0
because python needs to return a value here, but the expression keeps calling new functions and python can't return until it evaluates all of them to a final number (in this case at least).

The common practice is to save these variables as parameters, and pass them along the chain. It seems in your case, you would want to pass total as an additional parameter, and update it as needed.
There's also a neat functional way to do it in python
t=raw_input()
print reduce(lambda a, b: a+b, map(int,t))
This is recursive in nature.

Some pointers:
Your default case should return an actual number (0 in your case) and not just print done.
total = + first is setting total to first, not adding first to total. You would need total += first to do the latter.
The trick with "retaining" the value of your current total is to "save" it in the recursive call-chain itself by passing it along with each call. You won't need a global variable or a default parameter to do this.
Here's a solution:
def recursive_me(mystring):
if not mystring: # True if mystring is empty
return 0
return int(mystring[0]) + recursive_me(mystring[1:])
print(recursive_me("4567")) # 22

Here is a solution that uses the LEGB scope rule to avoid creating a new string instance on every recursive call
def sum_str(mystring):
def recursive_me(pos):
cur_char = int(mystring[pos])
if pos:
return cur_char + recursive_me(pos-1)
else:
return cur_char
return recursive_me(len(mystring)-1)
s = '4567'
print('summing', s)
print(sum_str(s))
However, indexing can be avoided as well by iterating on the string
def sum_str(mystring):
def recursive_me(itx):
try:
cur_char = int(next(itx))
return cur_char + recursive_me(itx)
except StopIteration:
return 0
return recursive_me(iter(mystring))
Obviously, both solutions produce
summing 4567
22

Related

How to fix inconsistent return statement in python?

I am new to python and i have this project I am working on a small project with two functions where the first returns the index of the first time a difference is spotted in a string. The next function does that but in a list of strings. Now, due to my being an amateur, i have used an excessive amount of if and else statements which resulted in too many return statements especially in the second function, and i get the error [R1710: inconsistent-return-statements]. How do i fix it and can anybody give me clear examples to better pieces of code? Sorry for the question being so long.
IDENTICAL = -1
def singleline_diff(line1, line2):
"""
Inputs:
line1 - first single line string
line2 - second single line string
Output:
Returns the index where the first difference between
line1 and line2 occurs.
Returns IDENTICAL if the two lines are the same.
"""
len1 = len(line1)
len2 = len(line2)
minimum_length = min(len1, len2)
if len1 != len2:
if minimum_length == 0:
return 0
for idx in range(minimum_length):
if line1[idx] == line2[idx]:
pass
else:
return idx
return idx + 1
for idx in range(len1):
if line1[idx] == line2[idx]:
pass
else:
return idx
return IDENTICAL
def multiline_diff(lines1, lines2):
"""
Inputs:
lines1 - list of single line strings
lines2 - list of single line strings
Output:
Returns a tuple containing the line number (starting from 0) and
the index in that line where the first difference between lines1
and lines2 occurs.
Returns (IDENTICAL, IDENTICAL) if the two lists are the same.
"""
line_no = singleline_diff(lines1, lines2)
len_lines1, len_lines2 = len(lines1), len(lines2)
if len_lines1 == len_lines2:
if (len_lines1 or len_lines2) == 0:
if len_lines1 == len_lines2:
return (IDENTICAL, IDENTICAL)
else:
idx = singleline_diff(lines1[line_no], lines2[line_no])
return (line_no, idx)
else:
idx = singleline_diff(lines1[line_no], lines2[line_no])
if line_no == IDENTICAL:
return (IDENTICAL, IDENTICAL)
elif line_no != IDENTICAL:
return (line_no, idx)
else:
return (line_no, 0)
Where was a semantic mistake in OP's code is in Abhishek Arya's answer
TL;DR - early return:
def your_function():
if not should_do():
return # NO RETURN VALUE!
# rest of the function
...yes, this will no longer emit the inconsistent-return-statements ;)
This Q/A pops also when you search for inconsistent-return-statements, I want to give a brief "common problems" guide for those.
Case A: return value is irrelevant, you just want to exit function early
There are cases, where there are functions (or "procedures" if you want to get technical about it) that just do something, but are not expected to have any return values AT ALL,
at the same time, there may be e.g. some sort of check at the start of the function whether this function run even makes sense, what may first come to your mind, is wrapping the whole function code in an if statement:
def your_function(article):
if display_content():
content = get_content(article)
# do some extensive logic to generate final content
# ...
print(content)
...this is oversimplified, but let's hope you can imagine how such coding can pretty quickly fall into a "spaghetti code" if there are more checks and more code in general + it also steals that one "tab" of a space that you so desperately need to fit into your project's max line length.
Luckily, same as in many other programming languages, there IS a way of an early ending of a function by returning at ANY place within the function run, meaning in any "Control Flow" - including if/elif/else, for/while loops, ...
Now you'd probably jump quick to just return None, False, etc. although it would work, you'd still get the pylint inconsistent-return-statements warning - to understand why let's see the warning's message:
Either all return statements in a function should return an
expression, or none of them should. pylint(inconsistent-return-statements)
From pylint's point of view, if you put anything after the return it will be considered as an expression. So what to do? Actually, in Python, you CAN return "nothing" (again this is not unique to Python)
def your_function(article):
if not display_content():
return
content = get_content(article)
# do some extensive logic to generate final content
# ...
print(content)
Although in Python returning "nothing" should be (and technically, to my knowledge, it is) an equivalent of return None, by physically writing "None" you are expressing the intention no matter the implicity of it.
Don't confuse this though with pylint(assignment-from-none) (Assigning result of a function call, where the function returns None) - where both "return" AND "return None" are considered as returning None!
Case B: Your function has a case when it doesn't return
Quite common mistake especially in a larger code is to create a code part which results in simply not returning anything. This is not exactly OP's case, since they used just a negation of the same condition, but pylint doesn't know that, so here's its thought process:
if SOME_CONDITION: # ok, here's just another condition
return someReturnExpression # and ok, it returns SOMETHING, let's note that
elif OPPOSITE_OF_SOME_CONDITION: # ok, here's just another condition
return someReturnExpression # and ok, it returns SOMETHING, let's note that
# WAIT ! What?! THERE WAS NO "else:"! Hmmm...
# ...what happens if both conditions fail? NOTHING WOULD BE RETURNED!
# We need to make a warning about that!
# (fact that sometimes they return SOMETHING and sometimes NOTHING)
So this inconsistent-return-statements could be resolved with
if SOME_CONDITION: # ok, here's some condition
return someReturnExpression # and ok, it returns SOMETHING, let's note that
else: # ok, here's else
return someReturnExpression # and ok, it returns SOMETHING, let's note that
# Ok, so if returns SOMETHING, else returns SOMETHING,
# so SOMETHING is returned every time! that's good!
...this in itself works, but it will generate yet another pylint issue
Unnecessary "else" after "return" pylint(no-else-return)
See python actually encourages early returns since it often leads to a cleaner code.
return during function run ENDS(/exits) the function and pylint sees that - it sees that if the condition was true, the function code would simply end there - so what it, Abhishek Arya, me and many others suggest is simply continuing with the code after the if part:
if SOME_CONDITION:
return someReturnExpression
# ... some more code ...
# ... some more code ...
return someReturnExpression
Case C: Combination
Simply don't combine "just" return with return SOMETHING,
if you really need to return None, simply explicitly return None in that case
def get_article(id):
article = find_article(id)
if article.id == 0:
return None
return article
This is just an example, this is not how you'd really check for some articles ;)
Look at the code here:
if len_lines1 == len_lines2:
return (IDENTICAL, IDENTICAL)
else:
idx = singleline_diff(lines1[line_no], lines2[line_no])
return (line_no, idx)
You could have written the above thing like:
if len_lines1 == len_lines2:
return (IDENTICAL, IDENTICAL)
idx = singleline_diff(lines1[line_no], lines2[line_no])
return (line_no, idx)
You just don't need an else block to return this expression as this part of code will automatically be called if the control doesn't go into if block. Hope it helps.

How would you use the ord function to get ord("a") as 0?

For example, in python, when I type in ord("a") it returns 97 because it refers to the ascii list. I want ord("a") to return zero from a string that I created such as
alphabet = "abcdefghijklmnopqrstuvwxyz0123456789 .,?!"
so ord("b") would be 1 and ord("c") would be 2 ect.
How would I go about doing this?
You don't.
You're going about this the wrong way: you're making the mistake
This existing thing doesn't meet my needs. I want to make it meet my needs!
instead, the way to go about the problem is
This existing thing doesn't meet my needs. I need a thing that does meet my needs!
Once you realize that, the problem is now pretty straightforward. e.g.
DEFAULT_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789 .,?!"
def myord(x, alphabet=DEFAULT_ALPHABET):
return alphabet.find(x)
Something like this should do the trick:
def my_ord(c):
alphabet = "abcdefghijklmnopqrstuvwxyz0123456789 .,?!"
return alphabet.index(c)
If i've understood correctly, this is what you want:
alphabet = "abcdefghijklmnopqrstuvwxyz0123456789 .,?!"
def crypt(c, key=97):
return ord(c)-key
def decrypt(c, key=97):
return chr(c+key)
dst = [crypt(c) for c in alphabet]
src = [decrypt(c) for c in dst]
print dst
print ''.join(src)
You can create a dict to map from characters to indices and then do lookups into that. This will avoid repeatedly searching the string as other answers are suggesting (which is O(n)) and instead give O(1) lookup time with respect to the alphabet:
my_ord_dict = {c : i for i, c in enumerate(alphabet)}
my_ord_dict['0'] # 26
At that point you can easily wrap it in a function:
def my_ord(c):
return my_ord_dict['0']
Or use the bound method directly
my_ord = my_ord_dict.__getitem__
But you don't want to change the name that refers to a builtin function, that'll confuse everyone else trying to use it that can see your change. If you are really trying to hurt yourself you can replace my_ord with ord in the above.

Understanding a Python function

I need some help understanding a function that i want to use but I'm not entirely sure what some parts of it do. I understand that the function is creating dictionaries from reads out of a Fasta-file. From what I understand this is supposed to generate pre- and suffix dictionaries for ultimately extending contigs (overlapping dna-sequences).
The code:
def makeSuffixDict(reads, lenSuffix = 20, verbose = True):
lenKeys = len(reads[0]) - lenSuffix
dict = {}
multipleKeys = []
i = 1
for read in reads:
if read[0:lenKeys] in dict:
multipleKeys.append(read[0:lenKeys])
else:
dict[read[0:lenKeys]] = read[lenKeys:]
if verbose:
print("\rChecking suffix", i, "of", len(reads), end = "", flush = True)
i += 1
for key in set(multipleKeys):
del(dict[key])
if verbose:
print("\nCreated", len(dict), "suffixes with length", lenSuffix, \
"from", len(reads), "Reads. (", len(reads) - len(dict), \
"unambigous)")
return(dict)
Additional Information: reads = readFasta("smallReads.fna", verbose = True)
This is how the function is called:
if __name__ == "__main__":
reads = readFasta("smallReads.fna", verbose = True)
suffixDicts = makeSuffixDicts(reads, 10)
The smallReads.fna file contains strings of bases (Dna):
"> read 1
TTATGAATATTACGCAATGGACGTCCAAGGTACAGCGTATTTGTACGCTA
"> read 2
AACTGCTATCTTTCTTGTCCACTCGAAAATCCATAACGTAGCCCATAACG
"> read 3
TCAGTTATCCTATATACTGGATCCCGACTTTAATCGGCGTCGGAATTACT
Here are the parts I don't understand:
lenKeys = len(reads[0]) - lenSuffix
What does the value [0] mean? From what I understand "len" returns the number of elements in a list.
Why is "reads" automatically a list? edit: It seems a Fasta-file can be declared as a List. Can anybody confirm that?
if read[0:lenKeys] in dict:
Does this mean "from 0 to 'lenKeys'"? Still confused about the value.
In another function there is a similar line: if read[-lenKeys:] in dict:
What does the "-" do?
def makeSuffixDict(reads, lenSuffix = 20, verbose = True):
Here I don't understand the parameters: How can reads be a parameter? What is lenSuffix = 20 in the context of this function other than a value subtracted from len(reads[0])?
What is verbose? I have read about a "verbose-mode" ignoring whitespaces but i have never seen it used as a parameter and later as a variable.
The tone of your question makes me feel like you're confusing things like program features (len, functions, etc) with things that were defined by the original programmer (the type of reads, verbose, etc).
def some_function(these, are, arbitrary, parameters):
pass
This function defines a bunch of parameters. They don't mean anything at all, other than the value I give to them implicitly. For example if I do:
def reverse_string(s):
pass
s is probably a string, right? In your example we have:
def makeSuffixDict(reads, lenSuffix = 20, verbose = True):
lenKeys = len(reads[0]) - lenSuffix
...
From these two lines we can infer a few things:
the function will probably return a dictionary (from its name)
lenSuffix is an int, and verbose is a bool (from their default parameters)
reads can be indexed (string? list? tuple?)
the items inside reads have length (string? list? tuple?)
Since Python is dynamically typed, this is ALL WE CAN KNOW about the function so far. The rest would be explained by its documentation or the way it's called.
That said: let me cover all your questions in order:
What does the value [0] mean?
some_object[0] is grabbing the first item in a container. [1,2,3][0] == 1, "Hello, World!"[0] == "H". This is called indexing, and is governed by the __getitem__ magic method
From what I understand "len" returns the number of elements in a list.
len is a built-in function that returns the length of an object. It is governed by the __len__ magic method. len('abc') == 3, also len([1, 2, 3]) == 3. Note that len(['abc']) == 1, since it is measuring the length of the list, not the string inside it.
Why is "reads" automatically a list?
reads is a parameter. It is whatever the calling scope passes to it. It does appear that it expects a list, but that's not a hard and fast rule!
(various questions about slicing)
Slicing is doing some_container[start_idx : end_idx [ : step_size]]. It does pretty much what you'd expect: "0123456"[0:3] == "012". Slice indexes are considered to be zero-indexed and lay between the elements, so [0:1] is identical to [0], except that slices return lists, not individual objects (so 'abc'[0] == 'a' but 'abc'[0:1] == ['a']). If you omit either start or end index, it is treated as the beginning or end of the string respectively. I won't go into step size here.
Negative indexes count from the back, so '0123456'[-3:] == '456'. Note that [-0]is not the last value,[-1]is. This is contrasted with[0]` being the first value.
How can reads be a parameter?
Because the function is defined as makeSuffixDict(reads, ...). That's what a parameter is.
What is lenSuffix = 20 in the context of this function
Looks like it's the length of the expected suffix!
What is verbose?
verbose has no meaning on its own. It's just another parameter. Looks like the author included the verbose flag so you could get output while the function ran. Notice all the if verbose blocks seem to do nothing, just provide feedback to the user.

Python: Cannot Assign Function Call

I am having a problem such as:
def function (number):
for number in list:
number = number + 1
For example function(1):
for number in range(1,5):
number = number + 1
Error come back as "can't assign function call"
I would like to use that variable as a value for further calculations.
Help!
I think you have two problems. First, you are not naming your function or declaring it properly; you should do this:
def f(number):
...
Second, you are naming the function parameter number but on the next line you seem to be treating list as though it were the parameter. I think you mean to do this instead:
def f(list):
for number in my_list:
...
Functions in python are defined using the def keyword:
def function_name(number):
for number in my_list:
number = number + something
you have to use def to define a function

"Function object is unsubscriptable" in basic integer to string mapping function

I'm trying to write a function to return the word string of any number less than 1000.
Everytime I run my code at the interactive prompt it appears to work without issue but when I try to import wordify and run it with a test number higher than 20 it fails as "TypeError: 'function' object is unsubscriptable".
Based on the error message, it seems the issue is when it tries to index numString (for example trying to extract the number 4 out of the test case of n = 24) and the compiler thinks numString is a function instead of a string. since the first line of the function is me defining numString as a string of the variable n, I'm not really sure why that is.
Any help in getting around this error, or even just help in explaining why I'm seeing it, would be awesome.
def wordify(n):
# Convert n to a string to parse out ones, tens and hundreds later.
numString = str(n)
# N less than 20 is hard-coded.
if n < 21:
return numToWordMap(n)
# N between 21 and 99 parses ones and tens then concatenates.
elif n < 100:
onesNum = numString[-1]
ones = numToWordMap(int(onesNum))
tensNum = numString[-2]
tens = numToWordMap(int(tensNum)*10)
return tens+ones
else:
# TODO
pass
def numToWordMap(num):
mapping = {
0:"",
1:"one",
2:"two",
3:"three",
4:"four",
5:"five",
6:"six",
7:"seven",
8:"eight",
9:"nine",
10:"ten",
11:"eleven",
12:"twelve",
13:"thirteen",
14:"fourteen",
15:"fifteen",
16:"sixteen",
17:"seventeen",
18:"eighteen",
19:"nineteen",
20:"twenty",
30:"thirty",
40:"fourty",
50:"fifty",
60:"sixty",
70:"seventy",
80:"eighty",
90:"ninety",
100:"onehundred",
200:"twohundred",
300:"threehundred",
400:"fourhundred",
500:"fivehundred",
600:"sixhundred",
700:"sevenhundred",
800:"eighthundred",
900:"ninehundred",
}
return mapping[num]
if __name__ == '__main__':
pass
The error means that a function was used where there should have been a list, like this:
def foo(): pass
foo[3]
You must have changed some code.
By the way, wordify(40) returned "fourty". I spell it "forty"
And you have no entry for zero
In case someone looks here and has the same problem I had, you can also get a pointer to a function object if the wrong variable name is returned. For example, if you have function like this:
def foo():
my_return_val = 0
return return_val
my_val = foo()
then my_val will be a pointer to a function object which is another cause to "TypeError: 'function' object is unsubscriptable" if my_val is treated like a list or array when it really is a function object.
The solution? Simple! Fix the variable name in foo that is returned to my_return_val.

Categories