Using print() inside recursive functions in Python3 - python

I am following the book Introduction to Computing Using Python, by Ljubomir Perkovic, and I am having trouble with one of the examples in recursion section of the book. The code is as follows:
def pattern(n):
'prints the nth pattern'
if n == 0: # base case
print(0, end=' ')
else: #recursive step: n > 0
pattern(n-1) # print n-1st pattern
print(n, end=' ') # print n
pattern(n-1) # print n-1st pattern
For, say, pattern(1), the output should be 0 1 0, and it should be displayed horizontally. When calling the function pattern(1), nothing prints out, however. But if this is followed by a print statement without arguments, then the results are displayed.
>>>pattern(1)
>>>print()
0 1 0
If I remove the end argument of the print() functions inside the recursive function, I get correct output (albeit it displays it vertically):
>>> pattern(1)
0
1
0
This makes me think that the recursive code itself is correct (plus I confirmed it was with the source provided by the book's website, and with the errata sheet). I am not sure, however, why the print statement isn't printing the output as the functions run, if the end parameter is included. Any help would be greatly appreciated.

The print function doesn't always flush the output. You should flush it explicitly:
import sys
def pattern(n):
'prints the nth pattern'
if n == 0: # base case
print(0, end=' ')
else: #recursive step: n > 0
pattern(n-1) # print n-1st pattern
print(n, end=' ') # print n
pattern(n-1) # print n-1st pattern
sys.stdout.flush()
Note that on python3.3 print has a new keyword argument flush that you can use to forcibly flush the output(and thus avoid using sys.stdout.flush).
On a general note I'd decouple the output from the pattern, doing, for example:
def gen_pattern(n):
if n == 0:
yield 0
else:
for elem in gen_pattern(n-1):
yield elem
yield n
for elem in gen_pattern(n-1):
yield elem
def print_pattern(n):
for elem in gen_pattern(n):
print(elem, end=' ')
sys.stdout.flush()
This makes the code more flexible and reusable, and has the advantage of calling flush only once, or you could also call it once every x elements(actually I believe print already does this. It flushes if trying to write many characters on the screen).
In python3.3 the code could be simplified a little:
def gen_pattern(n):
if n == 0:
yield 0
else:
yield from gen_pattern(n-1)
yield n
yield from gen_pattern(n-1)

The reason is that when end is used with some value other than a "\n" then the print function accumulates the whole value and prints the output only when a newline is to be printed or the loop is over.
See the difference in these two programs:
In [17]: for x in range(5):
print(x,end=" ")
if x==3:
print(end="\n")
sleep(2)
....:
0 1 2 3 #first this is printed
4 #and then after a while this line is printed
In [18]: for x in range(5):
print(x,end=" ")
if x==3:
print(end="\t")
sleep(2)
....:
0 1 2 3 4 #whole line is printed at once

Related

My code works but sometimes gets into an infinite loop

So i got an assignment from school that the code should pick a string, remove the first and the last index, then randomize the middle letters and give back the string with the first and the last index again attached. The word should be at least 4 characters long and schould not give back the original string. It is warking and all, but it after a few attempts at giving a 4 letter word gets into an infinite loop and I can't figure out why. It's a python code. Thank you for your help. Also some variables are in my laguage which shouldn't be a problem...just to clarify the weird variable names.
import random
n=0
while n<4:
slovo=input('Zadajte vase slovo: ')
n=len(slovo)
l=[]
def shufle(slovo,l):
for i in range(len(slovo)):
if i==0:
continue
if i==len(slovo)-1:
continue
else:
l.append(slovo[i])
random.shuffle(l)
while True:
shufle(slovo,l)
s=slovo[0]
for i in l:
s+=i
s+=slovo[-1]
if s==slovo:
continue
elif len(s)!=len(slovo):
continue
else:
print(s)
break
Here's a tip: if your function is always expecting the same input for one of its parameters, than that parameter is probably not necessary. This is the case with passing empty lists or similar objects to functions. There was also a check if s and slovo are the same size which is not needed so I removed it. Try this:
import random
n=0
while n<4:
slovo=input('Zadajte vase slovo: ')
n=len(slovo)
def shufle(slovo):
l = []
for i in range(len(slovo)):
if i == 0:
continue
if i == len(slovo)-1:
continue
else:
l.append(slovo[i])
random.shuffle(l)
return l
while True:
l = shufle(slovo)
s = slovo[0]
for i in l:
s += i
s += slovo[-1]
if s == slovo:
continue
else:
print(s)
break

how to split the output of the Python code?

I have following code, which should print an output of k numbers around n number, and instead the n number the code should replace by *:
def numbers_around(n, k):
for cislo in range(n-k, n+k+1):
if cislo == n:
print("*", end=" ")
else:
print(cislo, end=" ")
numbers_around(8, 3)
numbers_around(10, 2)
The output should be:
5 6 7 * 9 10 11
8 9 * 11 12
But my output is all in one line:
5 6 7 * 9 10 11 8 9 * 11 12
You are using the parameter end = " " in the print function, which replaces the default end used by python which is starting new line; if you want to start new line after each printing, just add print() at the end.
the full function should be
def numbers_around(n, k):
for cislo in range(n-k, n+k+1):
if cislo == n:
print("*", end=" ")
else:
print(cislo, end=" ")
print()
Using end=" " tells the print function to output a space at the end, instead of the line break that it would normally output.
Therefore the output of the second function call starts on the same line as the output of the first function call ends.
You need to output an additional line break at the end of the numbers_around function.
To do that, just add an empty print() after the for loop:
def numbers_around(n, k):
for ...:
# ...
print()
The problem is that you're telling print() to put a space at the end instead of the newline character '\n' it normally uses. You could fix this by just adding another call to print() at the end, but actually, if you redesign the function a little bit, you can make it a lot simpler. By using the splat operator, you can print everything at once.
Option 1: Use a generator expression or list comprehension instead of a for-loop.
def numbers_around(n, k):
r = range(n-k, n+k+1)
out = ('*' if i==n else i for i in r)
print(*out)
Option 2: Instead of replacing n, get the two ranges around n and put a '*' in the middle.
def numbers_around(n, k):
r1 = range(n-k, n)
r2 = range(n+1, n+k+1)
print(*r1, '*', *r2)

How to print two statements from different functions on the same line in Python

I'm trying to print two output statements on the same line in Python 2.7 (or 3.4). The print statements don't come one after the other Like print a/ print b. My program takes 329 (say) and returns that value in words - three hundred twenty nine. So it will determine the 300 part and print it then the 29 part and print that.
if (main == hundreds[index]):
print hundreds_words[index]
for location in range (0, 10):
if (difference == twenties[location]):
print twenties_words[location]
I want to print the twenty nine on the same line as the three hundred. I suppose I could try and rig up a solution but I would like to know if Python has a procedure to do that.
Yes, it does. You just need to tell print not to add a new-line after the first one. In python2, you do this by adding a trailing comma: print mystring,. In python3, print is a function that has the end keyword argument: print(mystring, end="")
The easy way is to rewrite your number-to-words function and have it return a string instead of printing it.
The more involved way is to redirect stdout to capture the print output as a string.
Edit: looks like I made it more complicated than necessary; you could instead try
output_words = []
if (main == hundreds[index]):
output_words.append(hundreds_words[index])
for location in range (0, 10):
if (difference == twenties[location]):
output_words.append(twenties_words[location])
return " ".join(output_words)
In python 2 you can end a print statement with a , to indicate not to terminate in a newline, e.g.:
print hundreds_words[index],
In python 3 (or py2 with from __future__ import print_function) you explicitly need to define the end, e.g.:
print(hundreds_words[index], end=' ')
But ideally you would just collect all the result up in a list and join() them at the end...
result = []
if (main == hundreds[index]):
result.append(hundreds_words[index])
for location in range (0, 10):
if (difference == twenties[location]):
result.append(twenties_words[location])
print(' '.join(result))
Always design functions to return values, and not to print them (it's much more Pythonic!). Therefore, you should modify your code this way:
# FOR PYTHON 2.x
if (main == hundreds[index]):
print hundreds_words[index], # Note the comma
for location in range (0, 10):
if (difference == twenties[location]):
print twenties_words[location]
# FOR PYTHON 3.x
if (main == hundreds[index]):
print(hundreds_words[index], end=" ") # end=" " will override the default '\n' and leave a space after the string
for location in range (0, 10):
if (difference == twenties[location]):
print(twenties_words[location])
There's also a third option, more scalable: to wrap all datas in a list, and then print everything.
printable = []
if (main == hundreds[index]):
printable += hundreds_words[index]
for location in range (0, 10):
if (difference == twenties[location]):
printable += twenties_words[location]
print(" ".join(printable))

I need to count like characters in the same position in python, but I have no idea how to get it right, as i am new to the program

Write a Python script that asks the user to enter two DNA
sequences with the same length. If the two sequences have
different lengths then output "Invalid input, the length must
be the same!" If inputs are valid, then compute how many dna bases at the
same position are equal in these two sequences and output the
answer "x positions of these two sequences have the same
character". x is the actual number, depending on the user's
input.
Below is what I have so far.
g=input('Enter DNA Sequence: ')
h=input('Enter Second DNA Sequence: ')
i=0
count=0
if len(g)!=len(h):
print('Invalid')
else:
while i<=len(g):
if g[i]==h[i]:
count+=1
i+=1
print(count)
Do this in your while loop instead (choose better variable names in your actual code):
for i, j in zip(g, h):
if i == j:
count += 1
OR replace the loop entirely with
count = sum(1 for i, j in zip(g, h) if i == j)
This will fix your index error. In general, you shouldn't be indexing lists in python, but looping over them. If you really want to index them, the i <= len(g) was the problem... it should be changed to i < len(g).
If you wanted to be really tricky, you could use the fact that True == 1 and False == 0:
count = sum(int(i == j) for i, j in zip(g, h))
The issue here is your loop condition. Your code gives you an IndexError; this means that you tried to access a character of a string, but there is no character at that index. What it means here is that i is greater than the len(g) - 1.
Consider this code:
while i<=len(g):
print(i)
i+=1
For g = "abc", it prints
0
1
2
3
Those are four numbers, not three! Since you start from 0, you must omit the last number, 3. You can adjust your condition as such:
while i < len(g):
# do things
But in Python, you should avoid using while loops when a for-loop will do. Here, you can use a for-loop to iterate through a sequence, and zip to combine two sequences into one.
for i, j in zip(g, h):
# i is the character of g, and j is the character of h
if i != j:
count += 1
You'll notice that you avoid the possibility of index errors and don't have to type so many [i]s.
i<=len(g) - replace this with i<len(g), because index counting starts from 0, not 1. This is the error you are facing. But in addition, your code is not very pretty...
First way to simplify it, keeping your structure:
for i in range(len(g)):
if g[i]==h[i]:
count+=1
Even better, you can actually make it a one-liner:
sum(g[i]==h[i] for i in range(len(g)))
Here the fact that True is evaluated to 1 in Python is used.
g = raw_input('Enter DNA Sequence: ')
h = raw_input('Enter Second DNA Sequence: ')
c = 0
count = 0
if len(g) != len(h):
print('Invalid')
else:
for i in g:
if g[c] != h[c]:
print "string does not match at : " + str(c)
count = count + 1
c = c + 1
print(count)
if(len(g)==len(h)):
print sum([1 for a,b in zip(g,h) if a==b])
Edit: Fixed the unclosed parens. Thanks for the comments, will definitely look at the generator solution and learn a bit - thanks!

Loop Issue with Local Variable

I'm using Python (3.x) to create a simple program for an assignment. It takes a multiline input, and if there is more than one consecutive whitespace it strips them out and replaces it with one whitespace. [That's the easy part.] It must also print the value of the most consecutive whitespaces in the entire input.
Example:
input = ("This is the input.")
Should print:
This is the input.
3
My code is below:
def blanks():
#this function works wonderfully!
all_line_max= []
while True:
try:
strline= input()
if len(strline)>0:
z= (maxspaces(strline))
all_line_max.append(z)
y= ' '.join(strline.split())
print(y)
print(z)
if strline =='END':
break
except:
break
print(all_line_max)
def maxspaces(x):
y= list(x)
count = 0
#this is the number of consecutive spaces we've found so far
counts=[]
for character in y:
count_max= 0
if character == ' ':
count= count + 1
if count > count_max:
count_max = count
counts.append(count_max)
else:
count = 0
return(max(counts))
blanks()
I understand that this is probably horribly inefficient, but it seems to almost work. My issue is this: I would like to, once the loop is finished appending to all_lines_max, print the largest value of that list. However, there doesn't seem to be a way to print the max of that list without doing it on every line, if that makes sense. Any ideas on my convoluted code?
Just print the max of all_line_max, right where you currently print the whole list:
print(max(all_line_max))
but leave it at the top level (so dedent once):
def blanks():
all_line_max = []
while True:
try:
strline = input()
if strline:
z = maxspaces(strline)
all_line_max.append(z)
y = ' '.join(strline.split())
print(y)
if strline == 'END':
break
except Exception:
break
print(max(all_line_max))
and remove the print(z) call, which prints the maximum whitespace count per line.
Your maxspaces() function adds count_max to your counts list each time a space is found; not the most efficient method. You don't even need to keep a list there; count_max needs to be moved out of the loop and will then correctly reflect the maximum space count. You also don't have to turn the sentence into a list, you can directly loop over a string:
def maxspaces(x):
max_count = count = 0
for character in x:
if character == ' ':
count += 1
if count > max_count:
max_count = count
else:
count = 0
return max_count

Categories