function returns none instead of a tuple - python

I am using python 2.7. I wrote a code to generate passwords. For doing this, I used the random module to generate how many characters of different types(uppercase, lowercase, special and numbers) to be used to generate a password of a given length. When a wrote a function for this, it was supposed to return a tuple, but it returns None. Why is it happening?
I tried the casual debugging method of putting print statements in between and figuring out where it went wrong. Everything works just fine, except it returns None.
def passlen(a):
"""Gives length of different characters to be put into passwords"""
uplen=random.randrange(0, a)
lwlen=random.randrange(0, a)
speclen=random.randrange(0, a)
nmbrlen=random.randrange(0, a)
if uplen+lwlen+speclen+nmbrlen==a:
print (uplen, lwlen, speclen, nmbrlen)
return(uplen, lwlen, speclen, nmbrlen)
else:
passlen(a)
x=input("how many characters in the password?")
print(passlen(x))
Expected results are 4-tuples, but it gives None instead.

So you want four random numbers that add to a? Of course you can try choosing four random numbers until you find a set that adds up to a, but that might take a while for large values of a (and you definitely don't want to do this recursively).
Much better to choose three split points between 0 and a:
def passlen(a):
splits = sorted([random.randrange(0,a) for _ in range(3)])
uplen = splits[0]
lwlen = splits[1] - uplen
speclen = splits[2] - uplen - lwlen
nmbrlen = a - uplen - lwlen - speclen
return uplen, lwlen, speclen, nmbrlen

Thanks to Kamiccolo for trying to help out.
The function should look like this:
def passlen(a):
"""Gives length of different characters to be put into passwords"""
uplen=int(random.randrange(0, a))
lwlen=int(random.randrange(0, a))
speclen=int(random.randrange(0, a))
nmbrlen=int(random.randrange(0, a))
bab=(uplen, lwlen, speclen, nmbrlen)
if uplen+lwlen+speclen+nmbrlen==a:
return bab
else:
return passlen(a)
A duplicate thread also helped me in this.

Related

A Python function that takes how many rows and how many columns it should print pair of empty square brackets [] in grid form

I was trying to do my homework and ı stuck at 10th question.
I do not understand where is my mistake :(
our teacher want this;
>>> print_grid( 5, 3 )
[][][]
[][][]
[][][]
[][][]
[][][]
>>> print_grid( 4, 7 )
[][][][][][][]
[][][][][][][]
[][][][][][][]
[][][][][][][]
and there is my function;
def first(column ):
print("[]",end="")
for i in range(column-4):
print("[]",end="")
print("[]")
def second(column):
print("[]", end="")
for i in range(column-7):
print("[]",end ="")
def grid(column,raw):
first(column)
for i in range(raw):
for i in range(2):
second(column)
first(column)
grid(5,3)
my output;
[][][]
[][][][][]
[][][][][]
[][][][][]
and why is this printed out?
How can ı make it look like more beautifully :) ?
You have a lot of unnecessary code in your solution. You are printing rows * cols elements, so you should only need two nested loops here. Having multiple functions that loop more times than necessary will make this code hard to maintain, as well as hard to read.
Next, you shouldn't be doing any arithmetic on your row and column indices. The column-4 and row-7 just don't make sense, unless you are trying to print a more complex pattern, which doesn't seem to be the case.
You are on the right track with your print statements that have end="", since by default a newline will be printed that you don't want. An alternative to printing would be building a string and printing explicitly at the end.
Here are two possible options:
For a solution that explicitly "prints":
def grid_print(x, y):
for i in range(x):
for j in range(y):
print('[]', end='')
print()
However, it might be more useful to build a string of the grid, and return that from the function.
def grid_string(x, y):
return '\n'.join('[]' * y for _ in range(x))
>>> grid_print(3, 5)
[][][][][]
[][][][][]
[][][][][]
>>> print(grid_string(2, 6))
[][][][][][]
[][][][][][]

How to do this recursion method to print out every 3 letters from a string on a separate line?

I'm making a method that takes a string, and it outputs parts of the strings on separate line according to a window.
For example:
I want to output every 3 letters of my string on separate line.
Input : "Advantage"
Output:
Adv
ant
age
Input2: "23141515"
Output:
231
141
515
My code:
def print_method(input):
mywindow = 3
start_index = input[0]
if(start_index == input[len(input)-1]):
exit()
print(input[1:mywindow])
printmethod(input[mywindow:])
However I get a runtime error.... Can someone help?
I think this is what you're trying to get. Here's what I changed:
Renamed input to input_str. input is a keyword in Python, so it's not good to use for a variable name.
Added the missing _ in the recursive call to print_method
Print from 0:mywindow instead of 1:mywindow (which would skip the first character). When you start at 0, you can also just say :mywindow to get the same result.
Change the exit statement (was that sys.exit?) to be a return instead (probably what is wanted) and change the if condition to be to return once an empty string is given as the input. The last string printed might not be of length 3; if you want this, you could use instead if len(input_str) < 3: return
def print_method(input_str):
mywindow = 3
if not input_str: # or you could do if len(input_str) == 0
return
print(input_str[:mywindow])
print_method(input_str[mywindow:])
edit sry missed the title: if that is not a learning example for recursion you shouldn't use recursion cause it is less efficient and slices the list more often.
def chunked_print (string,window=3):
for i in range(0,len(string) // window + 1): print(string[i*window:(i+1)*window])
This will work if the window size doesn't divide the string length, but print an empty line if it does. You can modify that according to your needs

Python Printing on the same Line

The problem that I have is printing phone_sorter() and number_calls() all on the same lines. For instance it will print the two lines of phone_sorter but the number_calls will be printed right below it. I have tried the end='' method but it does not seem to work.
customers=open('customers.txt','r')
calls=open('calls.txt.','r')
def main():
print("+--------------+------------------------------+---+---------+--------+")
print("| Phone number | Name | # |Duration | Due |")
print("+--------------+------------------------------+---+---------+--------+")
print(phone_sorter(), number_calls())
def time(x):
m, s = divmod(seconds, x)
h, m = divmod(m, x)
return "%d:%02d:%02d" % (h, m, s)
def phone_sorter():
sorted_no={}
for line in customers:
rows=line.split(";")
sorted_no[rows[1]]=rows[0]
for value in sorted(sorted_no.values()):
for key in sorted_no.keys():
if sorted_no[key] == value:
print(sorted_no[key],key)
def number_calls():
no_calls={}
for line in calls:
rows=line.split(";")
if rows[1] not in no_calls:
no_calls[rows[1]]=1
else:
no_calls[rows[1]]+=1
s={}
s=sorted(no_calls.keys())
for key in s:
print(no_calls[key])
main()
Your key problem is that both phone_sorter and number_calls do their own printing, and return None. So, printing their return values is absurd and should just end with a None None line that makes no sense, after they've done all their own separate-line printing.
A better approach is to restructure them to return, not print, the strings they determine, and only then arrange to print those strings with proper formatting in the "orchestrating" main function.
It looks like they'll each return a list of strings (which they are now printing on separate lines) and you'll likely want to zip those lists if they are in corresponding order, to prepare the printing.
But your code is somewhat opaque, so it's hard to tell if the orders of the two are indeed corresponding. They'd better be, if the final printing is to make sense...
Added: let me exemplify with some slight improvement and one big change in phone_sorter...:
def phone_sorter():
sorted_no={}
for line in customers:
rows=line.split(";")
sorted_no[rows[1]]=rows[0]
sorted_keys = sorted(sorted_no, key=sorted_no.get)
results = [(sorted_no[k], k) for k in sorted_keys]
return results
Got it? Apart from doing the computations better, the core idea is to put together a list and return it -- it's main's job to format and print it appropriately, in concert with a similar list returned by number_calls (which appears to be parallel).
def number_calls():
no_calls=collections.Counter(
line.split(';')[1] for line in calls)
return [no_calls(k) for k in sorted(no_calls)]
Now the relationship between the two lists is not obvious to me, but, assuming they're parallel, main can do e.g:
nc = no_calls()
ps = phone_sorter()
for (duration, name), numcalls in zip(ps, nc):
print(...however you want to format the fields here...)
Those headers you printed in main don't tell me what data should be printed under each, and how the printing should be formatted (width of
each field, for example). But, main, and only main, should be
intimately familiar with these presentation issues and control them, while the other functions deal with the "business logic" of extracting the data appropriately. "Separation of concerns" -- a big issue in programming!

'float' object can't be interpreted as int, but converting to int yields no output

So I'm trying to test if something is a palindrome. Here is my code:
This function returns a string of the first half of a larger string. ("TEST" returns "TE", "HELLO" returns "HE")
def takeStart(s):
start = ""
# The following determines the final index of the first half
if len(s)%2==0:
a = (len(s)/2)-1
else:
a = ((len(s)-1)/2)-1
for i in range(a):
start+=s[i]
return start
This function returns a string of the second half of a larger string. ("TEST" returns "ST", "HELLO" returns "LO")
def takeEnd(s):
end = ""
# The following determines the beginning index of the second half
if len(s)%2==0:
a = (len(s)/2)
else:
a = ((len(s)-1)/2)
for i in range(a,len(s)):
end+=s[i]
return end
This function flips a string. ("TEST" returns "TSET", "HELLO" returns "OLLEH")
def flip(s):
flipped = ""
for i in range(1,len(s)):
flipped+=s[len(s)-i]
flipped+=s[0]
return flipped
This code takes every product of two 3-digit numbers, and checks if it's a palindrome
for i in range(100,1000):
for q in range(100,1000):
a = i*q
if takeStart(str(a)) == flip(takeEnd(str(a))):
print(str(a))
When this code is run, it outputs:
Traceback (most recent call last):
File "[redacted]", line 39, in <module>
if takeStart(str(a)) == flip(takeEnd(str(a))):
File "[redacted]", line 14, in takeStart
for i in range(a):
TypeError: 'float' object cannot be interpreted as an integer
Alright, I thought I just convert a to an integer and all should be swell.
Doing that appears to remove all errors, but there is NO output whatsoever. (There are new lines every once and a while which makes me think it's working but not outputing any data)
Any ideas on why this is happening?
UPDATE: my code now:
def takeStart(s):
start = ""
if len(s)%2==0:
a = (len(s)//2)
else:
a = (len(s)-1)//2
return start[0:a]
def takeEnd(s):
end = ""
if len(s)%2==0:
a = (len(s)//2)
else:
a = ((len(s)-1)//2)
return end[int(a):len(s)]
def flip(s):
return s[::-1]
for i in range(100,1000):
for q in range(100,1000):
a = i*q
if takeStart(str(a)) == flip(takeEnd(str(a))):
print(str(a))
This is just outputting every single number.
I tested each method and they're returning empty strings. (I'm assuming), which is why every number is passing the palindrome check and printing.
First, using range(int(a)) and range(int(a), len(s)) will solve your error. As Jon Clements points out, you can solve that more easily by just using // instead of / to get integers in the first place. But either way, it's not causing any problems.
Your problem is that ranges, and just about everything related in Python, are half-open. So, your takeStart function is returning all the values up to, but not including, the half-way point—that is, it gives you H for HELLO, T for TEST, BIGG for BIGGERTEST.
Just get rid of the -1 on your a = … lines, and that will solve that problem.
And then it prints out a whole bunch of output lines, all palindromes, which I assume is what you were intending to do.
However, you're still not going to get any odd-length palindromes. For example, with 'MADAM', even when you get the functions right, takeStart(s) is MA, takeEnd(s) is DAM, flip(takeEnd(s)) is MAD, and that's not the same as MAD. Even though your functions are working right, they're not solving the problem. So there's a bug in your design as well as your implementation. If you think about it for a while, you should figure out how to make this work.
And, once you do, you should realize that takeStart and takeEnd can be simplified a lot. (Hint: In which cases do you really need to treat odd and even lengths differently?)
While we're at it, this:
foo = ""
for i in range(x, y):
foo += s[i]
return foo
… is just a verbose, slow, and easy-to-get-wrong way of writing this:
return foo[x:y]
And, likewise, your whole flipped function is just:
return s[::-1]
Pythons range() function does not support floats but numpys arange()
function does
To use arange() function, you need to install and import the numpy package.
We’ll here use the arange() function for generating a range of float numbers.
The arange() has the same signature as the built-in range() method. But we can pass float type arguments as parameters to this function.
import numpy
arange (start, stop, step)
In a full code example this looks as follows:
from numpy import arange
print("Float range using NumPy arange():")
print("\nTest 1:")
for i in arange(0.0, 1.0, 0.1):
print(i, end=', ')

can I make it parallelized?

it an answer for Euler project #4.
A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 99.
Find the largest palindrome made from the product of two 3-digit numbers.
Answer:
906609
code is:
from multiprocessing import Pool
from itertools import product
def sym(lst):
rst=[]
for x,y in lst:
tmp=x*y
if rec(tmp):
rst.append(tmp)
return rst
def rec(num):
num=str(num)
if num == "".join(reversed(num)): return True
else: return False
if __name__ == "__main__":
pool=Pool(processes=8)
lst=product(xrange(100,1000),repeat=2)
rst=pool.map(sym,lst)
#rst=sym(lst)
print max(rst)
when I run this:
# TypeError:'int' object is not iterable
but I can't understand it...isn't list iterable? or is there an error in my code?
Your problem is with the function sym.
sym is being passed the first element of your product iterable. (e.g. lst = (100,100)). When you get to the for loop, you're iterating over lst and then trying to unpack it into two numbers -- equivalent to:
for x,y in (100,100):
...
Which fails for obvious reasons.
I think you probably want to get rid of the for loop all-together -- which was probably an artifact of your serial version.
def sym(lst):
x,y=lst
tmp=x*y
if rec(tmp):
return tmp
else:
return None #max will ignore None values since None > x is always False.
The traceback was somewhat cryptic -- Apparently the traceback gets returned to the Pool which then gets re-raised ... But the way it is done makes it a little difficult to track.
Sometimes, when debugging these things it is helpful to replace Pool.map() with the regular version of map. Then, any exceptions which get raised are raised on your main "thread" and the tracebacks can be a little easier to follow.

Categories

Resources