Function Calling Python basic - python

I'm trying to enter values from the tuple ('a',1), ('b',2),('c',3) into the function dostuff but i always get a return of None or False. i'm new to this to i'm sorry if this question is basic. I would appreciate any help.
I expect the result of this to be:
a1---8
b2---8
c3---8
Code:
def dostuff(stri,numb,char):
cal = stri+str(numb)+'---'+str(char)
return cal
def callit (tups,char):
for x in range(len(tups)):
dostuff(tups[x][0],tups[x][1],char)
print(callit([('a',1), ('b',2),('c',3)],8))

I think you're misunderstanding the return value of the functions: unless otherwise specified, all functions will return None at completion. Your code:
print(callit([('a',1), ('b',2),('c',3)],8))`
is telling the Python interpreter "print the return value of this function call." This isn't printing what you expect it to because the callit function doesn't have a return value specified. You could either change the return in your dostuff function like so:
def dostuff(stri,numb,char):
cal = stri+str(numb)+'---'+str(char)
print cal
def callit (tups,char):
for x in range(len(tups)):
dostuff(tups[x][0],tups[x][1],char)
callit([('a',1), ('b',2),('c',3)],8)
This changes the return on the third line into a print command, and removes the print command from the callit call.
Another option would be:
def dostuff(stri,numb,char):
cal = stri+str(numb)+'---'+str(char)
return cal
def callit (tups,char):
for x in range(len(tups)):
cal = dostuff(tups[x][0],tups[x][1],char)
print(cal)
callit([('a',1), ('b',2),('c',3)],8)
This takes the return value from the dostuff function and stores it in a variable named cal, which could then be printed or written to a file on disk.

as #n1c9 said, every Python function must return some object, and if there's no return statement written in the function definition the function will implicitly return the None object. (implicitly meaning that under the hood, Python will see that there's no return statement and returnNone)
However, while there's nothing wrong in this case with printing a value in a function rather than returning it, it's generally considered bad practice. This is because if you ever want to test the function to aid in debugging, you have to write the test within the function definition. While if you returned the value you could just test the return value of calling the function.
So when you're debugging this code you might write something like this:
def test_callit():
tups = [('a', 1), ('b', 2), ('c', 3)]
expected = 'a1---8\nb2---8\nc3---8'
result = callit(tups, 8)
assert result == expected, (str(result) + " != " + expected)
if you're unfamiliar with the assert statement, you can read up about it here
Now that you have a test function, you can go back and modify your code. Callit needs a return value, which in this case should probably be a string. so for the functioncallit you might write
def callit(tups, char):
result = ''
for x in range(len(tups)):
result += dostuff(tups[x][0], tups[x][1], char) + '\n'
result = result[:result.rfind('\n')] # trim off the last \n
return result
when you run test_callit, if you get any assertion errors you can see how it differs from what you expect in the traceback.
What I'm about to talk about isn't really relevant to your question, but I would say improves the readability of your code.
Python's for statement is very different from most other programming languages, because it actually acts like a foreach loop. Currently, the code ignores that feature and forces regular for-loop functionality. it's actually simpler and faster to write something like this:
def callit(tups, char):
result = ''
for tup in tups:
result += dostuff(tup[0], tup[1], char) + '\n'
result = result[:result.rfind('\n')] # trim off the last \n
return result

For a function to return a value in python it must have a return statement. In your callit function you lack a value to return. A more Pythonic approach would have both a value and iterate through the tuples using something like this:
def callit(tups, char):
x = [dostuff(a, b, char) for a, b in tups]
return x
Since tups is a list of tuples, we can iterate through it using for a, b in tups - this grabs both elements in the pairs. Next dostuff(a, b, char) is calling your dostuff function on each pair of elements and the char specified. Enclosing that in brackets makes the result a list, which we then return using the return statement.
Note you don't need to do:
x = ...
return x
You can just use return [dostuff(a, b, char) for a, b in tups] but I used the former for clarity.

You can use a list comprehension to do it in one line:
char = 8
point_list = [('a', 1), ('b', 2),('c', 3)]
print("\n".join(["{}{}---{}".format(s, n, char) for s, n in point_list]))
"{}{}---{}".format(s, n, char) creates a string by replacing {} by each one of the input in format, therefore "{}{}---{}".format("a", 1, 8) will return "a1---8"
for s, n in point_list will create an implicit loop over the point_list list and for each element of the list (each tuple) will store the first element in s and the second in n
["{}{}---{}".format(s, n, char) for s, n in point_list] is therefore a list created by applying the format we want to each of the tuples: it will return ["a1---8","b2---8","c3---8"]
finally "\n".join(["a1---8","b2---8","c3---8"]) creates a single string from a list of strings by concatenating each element of the list to "\n" to the next one: "a1---8\nb2---8\nc3---8" ("\n" is a special character representing the end of a line

Related

What's the different between calling function with and without 'return' in recursion?

I tried to create recursive function for generating Pascal's triangle as below.
numRows = 5
ans=[[1],[1,1]]
def pascal(arr,pre,idx):
if idx==numRows:
return ans
if len(arr)!=idx:
for i in range (0,len(pre)-1,1):
arr+=[pre[i]+pre[i+1]]
if len(arr)==idx:
arr+=[1]
ans.append(arr)
pascal([1],arr,idx+1)
a = pascal([1],ans[1],2)
return a
The output I got was an empty list [ ]. But if I add return when calling pascal as
return pascal([1],arr,idx+1)
the output was correct [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]].
As I understand, a should have been assigned by return ans. Then why a failed to get an answer when calling pascal without return and why return is necessary in this case?
When you have recursion, you usually combine the returns in some way. Could be a sum, like fibonacci:
fibonacci(n+1) = fibonnaci(n)+fibonacci(n-1)
Or appending a line to a matrix, like your case. Anyway, if you don't have a return, you have no information to combine! Consider the fibonnaci case without return:
def fibonnaci(n):
if n<2:
return 1
fib_ans = fibonnaci(n-2)+fibonnaci(n-1)
In this case, if I called fibonnaci(0) or fibonnaci(1) the output would be 1, like you return ans if idx == numRows, but if I called fibonnaci(2), then the variable fib_ans would receive 2, which is the expected answer, but it would be available outside the scope of the funtion. Python "would add" return None to the end of my function, just below the fib_ans attribution. So, I need to return fib_ans
Well as far as i know, if you want to get a value back you need the "return" statement...
The point is if you don't have "return", you will be getting no values back...
Hopefully this helps..
For all algol languages that has a return keyword it exits the nearest function completely and the result of it is the result of the expression of the return argument. eg.
def test(v):
if v == 0:
return someFun(10)
...
If v is zero the result of the function is the value returned by someFun(10). The rest of the function denoted by ... is never executed unless v is nonzero.
If we write the same without return:
def test(v):
if v == 0:
someFun(10)
...
Now, when v is zero someFun(10) is still called, but the value returned by it is discarded and in order for it to have any true meaning someFun needs to do some side effects, like printing, storing values, updating object. In addition all the rest of the function denoted by ... is then continued once someFun(10) is done.
For Python and many other languages not having a return at all doesn't mean it doesn't return anything. In Python there is an invisible return None in the last line of every function/method.
When you do pascal([1],arr,idx+1), you are doing the recursive call but then discarding the value which it returns. If you want to return it to the caller, then you need to use explicitly return pascal(...).
In fact recursion is not necessary in this example anyway. You could easily refactor your code to use a simple for loop. For example:
def pascal(numRows):
ans = [[1]]
for _ in range(1, numRows):
pre = ans[-1]
arr = [1]
for i in range(0,len(pre)-1,1):
arr+=[pre[i]+pre[i+1]]
arr+=[1]
ans.append(arr)
return ans
print(pascal(5))
(I'm using the name _ here as the for loop variable according to convention because it is a dummy variable not used inside the loop, but you could use something else e.g. row if you prefer.)
The above is as close to the original code as possible, but you should also consider using arr.append(value) in place of arr += [value] -- this would be the normal way to append a single value to a list.

How to add strings with each other during a loop?

For my programming class, I need to a create a program that takes in a string and two letters as an argument. Whenever the first letter appears in the string, it is replaced with the second letter. I can do this by making the final string into a list. However, our professor has stated that he wants it to be a string, not a list. The code shown below is what I used to make the program work if the final result was to appear in a list.
def str_translate_101(string, x, y):
new_list = []
for i in string:
if i == x:
new_list.append(y)
if i != x:
new_list.append(i)
return new_list
I tried to make one where it would output a string, but it would only return the first letter and the program would stop (which I'm assuming happens because of the "return")
def str_translate_101(string, old, new):
for i in string:
if i == old:
return new
else:
return i
I then tried using the print function, but that didn't help either, as nothing was outputted when I ran the function.
def str_translate_101(string, old, new):
for i in string:
if i == old:
print(new)
else:
print(i)
Any help would be appreciated.
An example of how the result should work when it works is like this:
str_translate_101('abcdcba', 'a', 'x') ---> 'xbcdcbx'
You can use join to merge a list into a string:
def str_translate_101(string, x, y):
new_list = []
for i in string:
if i == x:
new_list.append(y)
else:
new_list.append(i)
return ''.join(new_list)
or use the one-liner
str_tranlsate_101 = str.replace
The simplest solution would be, instead of storing the character in a list you can simply declare an empty string and in the 'if' block append the character to the string using the augmented '+=' operator. E.g.
if i == x:
concat_str += y
As for the return, basically, it will break out of the for loop and return to where the function was called from. This is because it only has 1 objective, which once achieved it will not bother to process any further code and simply go back to where the function was called from.

Setting a function to return its resulting value as a string

My goal is to have the function SRA_Accession return it's values as a string e.g "Value1,Value2,Value3" the code so far is
def SRA_Accession():
SRA=1293518
while (SRA < 1293618):
SRA=SRA+1
print "SRA"+str(SRA)
if False:
break
the lack of tabs are making this not work and you need a return statement which returns everything.
def SRA_Accession():
SRA=1293518
my_list = []
while (SRA < 1293618):
SRA=SRA+1
my_list.append("SRA"+str(SRA))
return ','.join(my_list)
Judging by the way you are writing the statement I would say you were looking to use a yield statement which returns each SRA string all by itself. This means you will need to add commas outside the function like so.
def SRA_Accession():
SRA=1293518
while (SRA < 1293618):
SRA=SRA+1
yield "SRA"+str(SRA)
value = ','.join(list(SRA_Accession()))
print(value)

Python: Assertion error when converting a string to binary

I am getting AssertionError when testing some basic functions in my python program. This is the scenario:
I have written a function that converts a single letter into binary from ASCII:
def ascii8Bin(letter):
conv = ord(letter)
return '{0:08b}'.format(conv)
Next there's a function that uses the previous function to convert all the letters in a word/sentence into binary:
def transferBin(string):
l = list(string)
for c in l:
print ascii8Bin(c)
Now when I try to assert this function like this:
def test():
assert transferBin('w') == '01110111'
print "You test yielded no errors"
print test()
It throws an AssertionError. Now I looked up the binary alphabet and tripple checked: w in binary is definitely 01110111. I tried calling just the transferBin('w') and it yielded 01110111 like it should.
I am genuinely interested in why the assertion fails. Any insight is very much appreciated.
Your function doesn't return anything. You use print, which writes text to stdout, but you are not testing for that.
As such, transferBin() returns None, the default return value for functions without an explicit return statement.
You'll have to collect the results of each ascii8Bin() result into a list and join the results into a string:
def transferBin(string):
results = [ascii8Bin(c) for c in l]
return '\n'.join(results)
This'll use newlines to separate the result for each character; for your single character 'w' string that'll give you the expected string.
Note that you don't need to turn l in to a list; you can iterate over strings directly; you'll get individual characters either way.
You need to return, you are comparing to None not the string. python will return None from a function if you don't specify a return value.
def transferBin(s):
l = list(s)
for c in l:
return ascii8Bin(c) # return
You are basically doing assert None == '01110111', also if you are only going to have single character string simply return ascii8Bin(string), having a loop with a return like in your code will return after the first iteration so the loop is redundant.
If you actually have multiple characters just use join and just iterate over the string you don't need to call list on it to iterate over a string:
def transferBin(s):
return "".join(ascii8Bin(ch) for ch in s)
You can also just do it all in your transferBin function:
def transferBin(s):
return "".join('{0:08b}'.format(ord(ch)) for ch in s)

how to return the iterations over keys as a string?

I am trying to return a string that contains the values of 2 attributes of every object in a dictionary and it's key . Every line is a key and the 2 attributes of it's object. The problem is that since the return statement ends the function, i only get the first key. I can get the results with print but i need the function to return the result.This is my attempted function:
aemptystring = ""
for key in self.cases.keys():
a = key, self.cases[key].color, self.cases[key].thetype
b = str(a) + "\n"
result = aemptystring + b
return result
and its gives me this:
"((3, 0), 'blanc', 'pion')\n"
It only does it for 1 key .The dictionary cases has number tuples as a key like (3,0) and the attributes of its object are .color which can be "noir" or "blanc" and .thetype is "pion" or "dame"
if i use print(aemptystring + b)i get the iterations for each key like i want which is like this:
((3, 0), 'blanc', 'pion')
((5, 4), 'blanc', 'pion')
((2, 1), 'noir', 'pion')
((1, 6), 'noir', 'pion')
....etc
How can i get the function to return the result of the iterations like the print gives me?
I can't just use print because i need to use the return of this function later on.The return also needs to be a string.
You could either append the results to a list and return the list of results outside the for loop, or you could use something called a generator which allows your function to resume executing where it left off after returning a value.
def generate_stuff():
for key in self.cases.keys():
a = key, self.cases[key].color, self.cases[key].thetype
yield str(a) + "\n"
for result in generate_stuff():
print result
Don't return inside the loop. :)
You almost got there with the aemptystring. You just have to keep adding onto it.
result = ""
for key in self.cases.keys():
a = key, self.cases[key].color, self.cases[key].thetype
b = str(a) + "\n"
result = result + b
return result
But concatenating strings repeatedly is quadratic, so it's better to build a list and then join it.
lines = []
for key in self.cases.keys():
a = key, self.cases[key].color, self.cases[key].thetype
lines.append(str(a) + "\n")
return ''.join(lines)
And you can make this a bit shorter with .items() and some string formatting.
lines = []
for key, case in self.cases.items():
a = key, case.color, case.thetype
lines.append("{0!r}\n".format(a))
return ''.join(lines)
It's a little weird to return a big string of Python reprs like this, though. Curious: what is this string used for?

Categories

Resources