How to reset a variable assigned to function in Python 2.73? - python

so basically a guy helped me improve my code. The problem is, it's still dead disappointing and does not work. What I wanna do, is reset the lenRecur.number so I could use the function again, using other strings and getting correct answers (not too big answers)
I guess, the problem is with hasattr. But I can't remove it, because if I do, my string length calculator won't work.
Anyway, even if I add lenRecur.number = 0 after the function, it still doesn't work.
It's like impossible, because when the function hits "return", it's done, period. If I reset it before "return", it will return 0, not correct answer so yeah I'm in deep trouble here.
def lenRecur(aStr):
if not hasattr(lenRecur, 'number'):
lenRecur.number = 0
'''
aStr: a string
returns: int, the length of aStr
'''
if aStr == '':
return lenRecur.number
else:
lenRecur.number += 1
return lenRecur(aStr[:-1])
P.s. the goal of my program(?) / script(?) is to measure the length of input string, without using input() method. As trying to re-create the length() method, with using more primitive means.
The script will have to have many different inputs, so it shall reset.

If you just want a recursive strength-length function, that's easy:
def len_recur(a_str):
if not a_str:
return 0
else:
return 1 + len_recur(a_str[1:])
Of course that's not tail-recursive, but then Python doesn't optimize tail recursion anyway, so it doesn't matter.
And if you want it to be tail recursive just for the hell of it—or because you've read Paul Butler's trick for Tail Recursion in Python and want to try it out—you still don't want to do that by storing the accumulator as an attribute of the function. Just use the usual trick of defining a local function (or using a mutable default parameter, if you prefer):
def len_tail_recur(a_str):
def tail(a_str, acc):
if not a_str:
return acc
else:
return tail(a_str[1:], acc+1)
return tail(a_str, 0)
If you want to convert this to a real tail-recursive function so it doesn't bomb on lists of 1001 elements, and don't understand the Paul Butler link above, see my answer to Get length of list in Python using recursion, which solves exactly this problem. (Another answer to that question also shows how to solve the problem with log N recursive calls instead of N, which is a different way of getting around the problem, unless you have impossibly long lists.)
All that being said, even though your implementation is the wrong way to do it, it actually works just fine. (So far, I've been PEP8-ifying your code to look more like idiomatic Python; from here on I'm just going to copy-paste as-is, but your real code should look like the above.)
def lenRecur(aStr):
if not hasattr(lenRecur, 'number'):
lenRecur.number = 0
'''
aStr: a string
returns: int, the length of aStr
'''
if aStr == '':
return lenRecur.number
else:
lenRecur.number += 1
return lenRecur(aStr[:-1])
print lenRecur('abc')
lenRecur.number = 0
print lenRecur('abcd')
This prints 3, then 4. Of course you have to set lenRecur.number from outside the function, because inside the function you still need the value. But you can solve that with the same kind of wrapper:
def lenRecur(aStr):
lenRecur.number = 0
'''
aStr: a string
returns: int, the length of aStr
'''
def recur(aStr):
if aStr == '':
return lenRecur.number
else:
lenRecur.number += 1
return recur(aStr[:-1])
return recur(aStr)

You don't have to use a state variable inside the function. If you want to make a recursive length calculator, then just do
def lenRecur (aStr):
if (aStr == ""):
return 0
else
return lenRecur (aStr [:-1]) + 1
Also note that this style has no error checking etc, but for the purposes of learning about recursion, it works fine.

If you're trying to understand recursion by implementing the length function using recursion then you can use something like this:
#!python
def lenRecur(something, curlen=0):
if something:
return lenRecur(something[1:], curlen+1)
else:
return curlen
... I won't claim that this is particularly good code. But it should work with any sort of sequence (string, list, tuple) ... anything for which the [1:] slice operation will work so long as it doesn't exceed the maximum recursion limit in your running Python instance.
In your example you're trying to implement a similar concept by using hasattr to "monkey patch" your function's object with a "number" attribute. In my example I'm using a default parameter as a way of passing the variable down into the recursive calls.
So in the initial call curlen is zero (calling this with the "optional" extra argument would give bogus results). From that call the function calls itself with a slice of the original sequence (string) that lops off the head (making it one shorter) and with the optional (curlen) argument incremented. At the end the string/sequence is of zero length, the zero is returned up through each of the previous (recursive) calls.
It's a lame way to accomplish this, and it could be a starting point for a discussion on tail recursion elimination (Google for it). But it will work without monkey patching your function/object.

Related

Trouble with top down recursive algorithm

I am trying to make word chains, but cant get around recursive searching.
I want to return a list of the words reuired to get to the target word
get_words_quicker returns a list of words that can be made by just changing one letter.
def dig(InWord, OutWord, Depth):
if Depth == 0:
return False
else:
d = Depth - 1;
wordC = 0;
wordS = [];
for q in get_words_quicker(InWord):
wordC+=1
if(OutWord == q):
return q
wordS.append(q)
for i in range(0,wordC):
return dig(wordS[i],OutWord,d)
Any help/questions would be much appreciated.
ANALYSIS
There is nowhere in your code that you form a list to return. The one place where you make a list is appending to wordS, but you never return this list, and your recursive call passes only one element (a single word) from that list.
As jasonharper already pointed out, your final loop can iterate once and return whatever the recursion gives it, or it can fall off the end and return None (rather than "nothing").
You have two other returns in the code: one returns False, and the other will return q, but only if q has the same value as OutWord.
Since there is no code where you use the result or alter the return value in any way, the only possibilities for your code's return value are None, False, and OutWord.
REPAIR
I'm afraid that I'm not sure how to fix this routine your way, since you haven't really described how you intended this code to carry out the high-level tasks you describe. The abbreviated variable names hide their purposes. wordC is a counter whose only function is to hold the length of the list returned from get_words_quicker -- which could be done much more easily.
If you can clean up the code, improve the data flow and/or documentation to something that shows only one or two disruptions in logic, perhaps we can fix the remaining problems. As it stands, I hesitate to try -- you'd have my solution, not yours.

Python - palindrome numbers

I am trying to write a program that finds the smallest pallindrome cube. My code:
def cubepal():
i=3
if str(i**3)==str(i**3)[::-1]:
return i**3
else:
i=i+1
cubepal()
I am pretty sure that the first part is correct, but the last three lines make the program run in an endless loop. In the end it only says the problem is on line
if str(i**3)==str(i**3)[::-1]:
I don't see why there is a problem. Could somebody help?
The reason is that you don't scope your variables correctly.
You call cubepal and cubepal initializes i=3 now when you perform the recursive call, i is a local variable equal to 3.
def cubepal(i):
if str(i**3)==str(i**3)[::-1]:
return i**3
else:
return cubepal(i+1)
and call it with cubepal(3).
Although for such cases, one better not uses recursion: if it is expected that i will be very large (this is not the case here), but it could be, for a memory-inefficient Python interpeter, result in a call-stack that scales with the value of the result.
A better way to handle this is I guess a while loop.
def cubepal():
i = 3
while str(i**3) != str(i**3)[::-1]:
i = i+1
return i**3
This will in general be more efficient as well, because calling a function leads to some overhead regarding bookkeeping and the call-stack.
You probably meant to do this:
def cubepal(i):
if str(i**3)==str(i**3)[::-1]:
return i**3
else:
return cubepal(i+1)
print(cubepal(3))
which yields "343".
Of course, there is no point to do it this way in Python since Python lacks TCO.

Python: My function returns "None" after it does what I want it to [duplicate]

This question already has answers here:
Why is "None" printed after my function's output?
(7 answers)
Closed 4 years ago.
Here is my program
def reverse(letters):
backwards = ""
i = len(letters) - 1
while i >= 0:
backwards = backwards + letters[i]
i = i - 1
print (backwards)
print (reverse("hello"))
It works, it prints out "olleh" but after, it prints "None" on a new line. And I'm asking why this is.
Obviously the program is to reverse a word, the code works, and without a function it doesn't print none, so I don't know why it does in the function. This is being used in another larger program, so I need it as a function, and because it's for school, I'm not allowed to simply use the .reverse() function. So I really need this code fixed rather than large changes, if possible.
function return None by default, so you should return backwards explicitly
also, you can use a pythonic way to solve the problem:
letters[::-1]
You can use a return statement to exit the function returning a value. If the function gets to the end without reaching a return statement, it will return None by default
def add1(x):
return x+1
def returnsNone():
pass
print(add1(2))
print(returnsNone())
Every function returns something in Python. If you don't explicitly return a value, Python has your function return None.
Your function doesn't actually return anything because print prints to stdout, while return actually returns a value. They may look the same in the REPL, but they're completely different.
So to fix your problem, return a value:
return backwards
Try just:
reverse(hello)
In fact with
print reverse(hello)
you are printing the return value of reverse. And that return value is None.
Let me give you few general advises:
reverse() in your code is a function with side effects (printing). You should avoid
functions with side effects when you don't need, consider having reverse() returning the word instead of printing it:
def reverse(letters):
backwards = ""
i = len(letters) - 1
while i >= 0:
backwards = backwards + letters[i]
i = i - 1
return backwards
print (reverse("hello"))
Moreover
i = len(letters) - 1
while i >= 0:
backwards = backwards + letters[i]
i = i - 1
is not easy to mantain and if you add functionality to the loop the decrement i=i-1 will be far from the place where it should 'conceptually' be. You should prefer having decrement together with the check:
for i in xrange(len(letters)-1,-1,-1):
backwards = backwards + letters[i]
When I'm lazy I write
myString = myString + fewChars
so I can understand you being lazy. But adding fewChars does not modify myString but creates a new one. If you are iteratively adding many chars, rarely the most efficient way is to add one by one. Consider using join().
For instance
letters = 'word'
lettersList = [letters[i] for i in xrange(len(letters)-1,-1,-1)]
myReversed ''.join(lettersList)
ok I agree is not readable and probably not even faster, but for larger strings it scales better than a newString = oldString + oneChar approach.
That said, more pythonic approaches
letters[::-1]
already suggested by someone faster than me typically works much better and are easy to be read by python programmers.
It makes sense if you think about it. Your reverse does not return anything - it just prints it's result. But when you write print (reverse("hello")), you are actually printing what reverse returns. Since it doesn't return anything, None is printed.
As mentioned earlier. If the python function does not come across a return statement it prints None by default. Making a small change as shown below fixes this:
def reverse(letters):
backwards = ""
i = len(letters) - 1
while i >= 0:
backwards = backwards + letters[i]
i = i - 1
return(backwards) # instead of print(backwards)
print(reverse("hello"))

Failing to understand recursion

New to Python and trying to understand recursion. I'm trying to make a program that prints out the number of times string 'key' is found in string 'target' using a recursive function, as in Problem 1 of the MIT intro course problem set. I'm having a problem trying to figure out how the function will run. I've read the documentation and some tutorials on it, but does anyone have any tips on how to better comprehend recursion to help me fix this code?
from string import *
def countR(target,key):
numb = 0
if target.find(key) == -1:
print numb
else:
numb +=1
return countR(target[find(target,key):],key)
countR('ajdkhkfjsfkajslfajlfjsaiflaskfal','a')
By recursion you want to split the problem into smaller sub-problems that you can solve independently and then combine their solution together to get the final solution.
In your case you can split the task in two parts: Checking where (if) first occurence of key exists and then counting recursively for the rest.
Is there a key in there:
- No: Return 0.
- Yes: Remove key and say that the number of keys is 1 + number of key in the rest
In Code:
def countR(target,key):
if target.find(key) == -1:
return 0
else:
return 1+ countR(target[target.find(key)+len(key):],key)
Edit:
The following code then prints the desired result:
print(countR('ajdkhkfjsfkajslfajlfjsaiflaskfal','a'))
This is not how recursion works. numb is useless - every time you enter the recursion, numb is created again as 0, so it can only be 0 or 1 - never the actual result you seek.
Recursion works by finding the answer the a smaller problem, and using it to solve the big problem. In this case, you need to find the number of appearances of the key in a string that does not contain the first appearance, and add 1 to it.
Also, you need to actually advance the slice so the string you just found won't appear again.
from string import *
def countR(target,key):
if target.find(key) == -1:
return 0
else:
return 1+countR(target[target.find(key)+len(key):],key)
print(countR('ajdkhkfjsfkajslfajlfjsaiflaskfal','a'))
Most recursive functions that I've seen make a point of returning an interesting value upon which higher frames build. Your function doesn't do that, which is probably why it's confusing you. Here's a recursive function that gives you the factorial of an integer:
def factorial(n):
"""return the factorial of any positive integer n"""
if n > 1:
return n * factorial(n - 1)
else:
return 1 # Cheating a little bit by ignoring illegal values of n
The above function demonstrates what I'd call the "normal" kind of recursion – the value returned by inner frames is operated upon by outer frames.
Your function is a little unusual in that it:
Doesn't always return a value.
Outer frames don't do anything with the returned value of inner frames.
Let's see if we can refactor it to follow a more conventional recursion pattern. (Written as spoiler syntax so you can see if you can get it on your own, first):
def countR(target,key):
idx = target.find(key)`
if idx > -1:
return 1 + countR(target[idx + 1:], key)
else:
return 0
Here, countR adds 1 each time it finds a target, and then recurs upon the remainder of the string. If it doesn't find a match it still returns a value, but it does two critical things:
When added to outer frames, doesn't change the value.
Doesn't recur any further.
(OK, so the critical things are things it doesn't do. You get the picture.)
Meta/Edit: Despite this meta article it's apparently not possible to actually properly format code in spoiler text. So I'll leave it unformatted until that feature is fixed, or forever, whichever comes first.
If key is not found in target, print numb, else create a new string that starts after the the found occurrence (so cut away the beginning) and continue the search from there.

Odd Even String- Python

Write a function named evenOddString() that takes a single string parameter.
If the length of the string parameter:
is odd: evenOddString() should return the string parameter.
is even, evenOddString() should return the string parameter concatenated with itself.
This is my code so far:
def evenOddString():
len(var) % 2 != 0
First, your evenOddString() function needs to take a parameter. For example:
def evenOddString(the_string_parameter):
print(the_string_parameter)
To call that function, you would have something like:
evenOddString('abc123')
which would print out abc123 on the console. In your case, you will want check the length of the_string_parameter and do some stuff with it "if" the length is even or odd. The if and elif statements will be helpful. See http://docs.python.org/tutorial/controlflow.html for docs on flow control.
You also want to return a value back out of your function. If I wanted to return the string unchanged, I would do something like:
def evenOddString(the_string_parameter):
return the_string_parameter
Note that I'm being a little vague here as this sounds like a homework assignment and I don't want to simply write all the code for you. Since you sound like a new programmer just starting out and in need of a good tutorial, I highly recommend you work through http://learnpythonthehardway.org/
define a function that take a parameter - Your definition does not take a parameter
get the length of that parameter - No problems here
if the length is odd, return the return the parameter - Your condition is correct, but you're not doing anything with the condition
else: return the parameter concatenated with itself - not implemented
def control4OddString(myString):
if len(myString) % 2: return myString
else: return myString+myString

Categories