How to pass information back and forth between scripts - python

I'm trying to pass information back and forth between 2 scripts. In one, we obtain a user input, in the other some modification is done to the user input, then back to the first one, we print out that modification.
#del2
def fun():
return int(user_input)+1
#script to run
user_input=input('some number')
from del2 import fun
print(fun())
So when we run our script, the user gives some input, the next line then runs the other script, which adds a value of 1 to the user inputted value, and then we print out that modified value. However, it appears you can't define a variable in one script, and have that defined variable transfer over to another script. Thus, I get this error when I try the above: NameError: name 'user_input' is not defined. I've tried to look at other posts regarding this, but they use tkinter and all are a bit too complicated/over my head to understand. So I made a very basic simple example to try and understand how this all works.
Edit:
I don't want to make another post, since its regarding the same issue. If I have to define every input used for every function, then it becomes quite crowded if you have multiple inputs. I.E.
#del2
def fun(user_input):
return int(user_input)+1
def fun2(user_input2):
return int(user_input2)+1
def fun3(user_input3):
return int(user_input3)+1
def fun4(user_input4):
return int(user_input4)+1
def fun5(user_input,user_input2,user_input3,user_input4):
return fun(user_input)+fun2(user_input2)+fun3(user_input3)+fun4(user_input4)
#script to run
user_input=input('some number')
user_input2=input('some number')
user_input3=input('some number')
user_input4=input('some number')
from del2 import fun5
print(fun5(user_input,user_input2,user_input3,user_input4))
Is there a better way to do this, so fun5 doesn't become extremely long if you have multiple inputs.

You need to define fun so it takes the variable as a parameter: def fun(user_input) then pass that variable to the imported function.
Also if you want user_inputs value to change after you call your fun() function you need to something like this:
#del2
def fun(user_input):
return int(user_input) + 1
#script to run
user_input = input('some number')
from del2 import fun
user_input = fun(user_input)
print(user_input)
Edit:
The fun() function isnt for just user_input. So you can use the same fun() function for another variables.
#del2
def fun(any_input): # i changed the variables name just to be clear
return int(any_input) + 1
#script to run
user_input = input('some number')
user_input2 = input('some number')
from del2 import fun
user_input = fun(user_input)
user_input2 = fun(user_input2)
print(user_input + ", " + user_input2)
and you can add the input variables to an array and do something like
#del2
def fun(any_input):
return int(any_input) + 2
def fun1(any_input):
return int(any_input) * 2
def fun2(any_input):
return int(any_input) // 2
def fun3(any_input):
return int(any_input) - 2
def fun5(input_array):
functions = [fun, fun1, fun2, fun3]
final = 0
if len(input_array) != 4:
raise Exception("Not enough functions for inputs")
for i in range(len(input_array)):
final += functions[i](input_array[i])
return final
#script to run
user_inputs = []
user_inputs.append(input('some number 0: ')) #you can use a for loop here too
user_inputs.append(input('some number 1: '))
user_inputs.append(input('some number 2: '))
user_inputs.append(input('some number 3: '))
from del2 import fun5
user_inputs = fun5(user_inputs)
print(user_inputs)

You can do this using the global keyword and a global variable within the imported module that is accessed by the different functions. Taking a simpler example that just adds or subtracts from a globally stored total:
# tally.py
total = 0
def add(n):
global total
total += n
def subtract(n):
global total
total -= n
# test_tally.py
import tally
tally.add(5)
tally.subtract(1)
print(tally.total)
However, global variables are bad. We do not generally think in terms of passing data back and forth between modules. The imported module is executed in its entirety at the time of importing, so data can only be passed to functions or other objects within the imported module.
Instead, modules often include classes, which can be used to generate objects that can store state. Data can be passed to these objects and stored within them. The objects can then operate upon the data and return different results by calling different methods of the object. This would be written like this:
# tally.py
class Tally(object):
def __init__(self):
self.total = 0
def add(self, n):
self.total += n
def subtract(self, n):
self.total -= n
# test_tally.py
from tally import Tally
tally = Tally()
tally.add(3)
tally.subtract(4)
print(tally.total)

Related

dictionary of functions returns every function

I am having difficulty returning a specific function from a dictionary of predefined functions. Here is my code:
import random
def bos1():
print ("function 1")
def bos2():
print ("function 2")
def bos3():
print("function 3")
def bos4():
print("function 4")
count = 0
while True :
if count <4:
bos = "bos"
poz = random.randint(3, 4)
bos = bos+str(poz)
bosdict = {'bos1': bos1(),'bos2':bos2(),'bos3':bos3(),'bos4':bos4()}
count += 1
print("please only printe one",bosdict[bos])
print("count:\n", count)
input("")
else:
bos = "bos"
poz = random.randint(1, 2)
bos = bos+str(poz)
bosdict = {'bos1': bos1(),'bos2':bos2(),'bos3':bos3(),'bos4':bos4()}
count += 1
print("please only printe one",bosdict['bos'])
print("count:\n", count)
input("")
I have created a successful version of this program that uses arithmetic functions. It will return the appropriate function relative to the string that has been concatenated upon each iteration. However with functions that are meant to return a string it returns all four functions in the dictionary on each iteration. Why is this happening and how can I make it behave the same as the arithmetic dictionary?
you're not creating a dictionary of function but a dictionary of function calls (which are None since your functions return nothing): all functions are executed when creating the dictionary.
Remove the () in your dict, you'll use it after retrieving the value in the dict to call the function:
bosdict = {'bos1': bos1,'bos2':bos2,'bos3':bos3,'bos4':bos4}
Call a random function like this:
bosdict[random.choice(list(bosdict.keys()))]()
or maybe simpler you don't need the keys in that case, only the values:
random.choice(list(bosdict.values()))()
or with the generated name from random index:
bosdict["bos{}".format(count)]()
note that dynamically calling the functions only has some interest if the functions are slow to compute or have a side-effect or parameters, else it's better to create a static dictionary (using return instead of print as Chris noted).

Missing Required Positional Arguments in Python

below is my an example of what i am trying to do in my code...
def func():
x = int (input ('enter x: '))
return x
def func2():
y = int (input( 'enter y: '))
return y
def func3(x,y):
print(randomint(x,y))
def main():
func()
func2()
func3()
main()
What i am wondering is, why cant i use the x and y variables that i have defined via input and returned at the end of my functions? When this program tries to run it says the functions are missing required arguments. Silly i know, i am new to python.
furthermore, how can i use variable in one function i am creating, that were defined within another separate function? thanks!
You stated that you know how to indent so I'm not going to discuss that, the problem at hand is that you will need to catch the return value from func and func2 after they are caught.
You can do so like this:
def func():
x = int (input ('enter x: '))
return x
def func2():
y = int (input( 'enter y: '))
return y
def func3(x,y): # there's two positional value so you will need to pass two values to it when calling
print(randomint(x,y))
def main():
x = func() # catch the x
y = func2() # catch the y
func3(x,y) # pass along x and y which acts as the two positional values
# if you're lazy, you can directly do:
# func3(func(), func2()) which passes the return values directly to func3
main()
Another method is to use the global statement, but that isn't the best way for your case.
Just a hint: if you are using the random module, the random integer is called by: random.randint(x,y)
Your variables only live within the functions, there is no way for func3 to get x and y, but you have defined x and y as parameters. So far you're just not passing them in. The following should do.
def func():
x = int (input ('enter x: '))
return x
def func2():
y = int (input( 'enter y: '))
return y
def func3(x,y):
print(randomint(x,y))
def main():
x_val = func()
y_val = func2()
func3(x_val, y_val)
main()
Or just like this, if you don't want to use variables.
Just remember, same name doesn't mean it's the same variable. The scope can be different (method, function, elsewhere), and the name makes the variable unique ("the same") withhin the same scope. That is similar across all higher programming languages, but also, scopes can intersect, and in different ways. So that reuse example above, might, for example work in JavaScript.
This is probably closest to what you attempted to achieve:
def inX():
return int (input ('enter x: '))
def inY():
return int (input( 'enter y: '))
def PrintRand(x,y):
print(randomint(x,y))
def main():
PrintRand(InX(),InY()) # is probably closest to what you attempted to do.
main()
note that those slight renames do not have an effect other than understanding the code, but good names of methods telling what they actually do, are very important. You read the code many more times. You write it once.

Why do I get and Error (NameError name 'first' not defined

def one():
if(slist[0] == 'a'):
first = 3
This code is on my 'numbers.py' file and I have it repeated for each letter of the alphabet. This file is imported to the main file I am launching.
import number
from number import *
if(len(number.string) == 1):
number.one()
print(number.first)
This code is on my main file and is supposed to print a '3' if you type 'A' when it asks you what you would like to decode
first variable is local to function one by default, it will no longer exist once exit the function, declare it as global to make it accessible outside function
And you might not need the line from number import * since you should be accessing from number namespace. Its not recommended to use import * also to avoid namespace pollution
first=None
def one():
global first
if(slist[0] == 'a'):
first = 3
A different solution could be to return your first variable, so that, you could use it in your mainas you want.
I show you:
def one():
if(slist[0] == 'a'):
first = 3
return first
''' you could use this instead '''
#return 3
and then, back in your main:
import number
if(len(number.string) == 1):
first = number.one()
print(first)

Calculations - Using functions

I am a bit confused over this.
I have a function. Inside that function it asks a number of questions, one is the following based on the number of gardens they have - so if they say they have 2 gardens it will ask this question twice and should add the 100 twice to the calculation:
gardens = int(input("How many gardens do you have: "))
def gard():
calc = 0
gardener = input("Do you need a gardener? Y or N ")
if gardener == "Y" or gardener == "y":
calc = calc + 100
else:
calc = calc + 0
for i in range(gardens):
gard()
How do I keep a running total outside of the function? When I put print(calc) inside the function it just displays 100 each time they say Y but doesn't add it together.
Edited to include updated code:
The eMake section (the IF statement) returns a value - but it only ever returns the first in the calculation at the end?
Also struggling to do the area section since there are numerous ws. It only stores the last value for the variable.
noGard = int(input("Enter number of gards which require cleaning: "))
#Defining variables
Calc = 0
Area = 0
emCalc = 0
#Room information
def GInfo():
global Calc
global Area
gName = input("Enter gard name: ")
noW = int(input("How many w are in the "+gName + "? "))
#Repeats the questions for each W
for i in range(noW):
Height = float(input("What is the w height of in metres? "))
Width = float(input("What is the w width in metres? "))
Area = Height * Width
#Asks if w needs to be removed
w = input("Does w need removing? Y or N ")
if w == "Y" or w == "y":
Calc = Calc + 70
else:
Calc = Calc + 0
print (" ")
#Returns the values
return Calc
return Area
#Calculate Sarea
#Identifying e
def e():
global emCalc
#eMake
eMake = input("What make of e - HH or NN? ")
if eMake == "HH" or "hh":
emCalc = emCalc + 200
elif eType == "NN" or "nn":
emCalc = emCalc + 50
else: print("You have entered an invalid e make")
#Returns the values
return emCalc
#Repeats the g information questions for each g
for i in range(noGard):
GInfo()
# Runs the E function
e()
#Print total without VAT
total = Calc + emCalc
print(total)
print(Area)
Your function should return the calculated value.
def gard():
...
return calc
total = 0
for _ in range(gardens):
total += gard()
print 'Total: ', total
The whole point of functions, really, is that they take parameters and return values. (Some languages, although not Python, refer to functions that don't do this as "procedures".)
That is what you need to do here: your gard function needs to return the value of calc. You probably don't want to actually do the addition inside the function itself, but if you did, you would also need to accept the current value of calc as a parameter, which you would pass in from your for loop.
Functions, in the strictest sense, do not have state. When writing functional programs, one typically aims to keep their functions pure, meaning that the result of the function does not depend on anything but its inputs and does not cause observable side effects.
But Python is not a purely functional language. It is an object-oriented procedural language which models functions as objects, and objects can be stateful. So you can do what you're aiming to, if you don't take the word "function" too literally.
The Right Thing™
Create a class which models your data and the operations on it:
>>> class F(object):
... def __init__(self):
... self.x = 0
... def f(self):
... self.x += 1
... return self.x
...
>>> my_f = F()
>>> my_f.f()
1
>>> my_f.f()
2
Fun and naughty ways
Add state to the function object, taking advantage of the fact that function bodies aren't executed until the function is called:
>>> def f():
... f.x += 1
... return f.x
...
>>> f.x = 0
>>> f()
1
>>> f()
2
If you want to do this transparently (that is, make it so that you don't have to add this state to the function right after defining it) you can close over the state by having a function create a function:
>>> def g():
... def func():
... func.x += 1
... return func.x
... func.x = 0
... return func
...
>>> f = g()
>>> f()
1
>>> f()
2
To take it a step further, create a decorator so you don't have to do any assignments after defining the function at all:
>>> def with_x(func):
... func.x = 0
... return func
...
>>> #with_x
... def f():
... f.x += 1
... return f.x
...
>>> f()
1
>>> f()
2
Or you can just use global to let a function refer to something outside of its local scope, not taking advantage of the fact that functions are objects:
>>> x = 0
>>> def f():
... global x
... x += 1
... return x
...
>>> f()
1
>>> f()
2
>>> x
2
Updates for your edit
Since you went with global I'll first refer you to a good question that explains global. Using global variables in a function other than the one that created them
Now, as for your particular problems:
The eMake section (the IF statement) returns a value - but it only ever returns the first in the calculation at the end?
Sure, there are a couple problems here and one of them is definitely a common one for beginners. or takes higher precedence than == so your condition parses like this:
if (eMake == "HH") or ("hh"):
This gets people all the time. In Python, if a value isn't a boolean and you put it in a conditional statement, it gets evaluated as a boolean using a series of truthiness rules. In this case a non-empty string is considered True so you are basically saying if (eMake == "HH") or True.
To fix this, fix the right-hand side of the condition:
if (eMake == "HH") or (eMake == "hh"):
By the way, you probably meant elif (eMake == "NN") or (eMake == "nn"): instead of elif eType == "NN" or "nn": because you never defined eType (and for the reason above, too.) If you type nn there you'll get an exception.
Also struggling to do the area section since there are numerous ws. It only stores the last value for the variable.
This is because you repeatedly assign to the same variable with Area = Height * Width. Since Area is global, it's the same variable every time you call GInfo(). If it wasn't global it would be a new variable every time you called the function, but then you would need to return it and assign the return value to a variable in order to save the value. Otherwise it would disappear since it was never assigned to anything.
Now, I don't know what you are trying to do with the areas you're calculating. Do you want to keep them separate or sum them together?
If you want to keep them separate, you'll need to use a data structure. In this case, you'd definitely want to use a list. Using the append() method of lists, you can add an item to the list. So it would look something like this:
areas = [] # empty list
def GInfo():
global areas
# the stuff before the loop
for i in range(noW):
Height = float(input("What is the w height of in metres? "))
Width = float(input("What is the w width in metres? "))
areas.append(Height * Width)
# the stuff after the loop
If you want to sum them together, just make sure you add each individual area calculation to the previous result, just like you did with Calc:
Area += Height * Width
One more thing: your GInfo() function is only returning Calc and not Area as well. Functions can only return one value. In the mathematical sense, a function is a many-to-one mapping between two sets. So in Python, a function ends at the return statement. Nothing else gets executed after that.
In order to get both the value of Calc as well as the value of Area from the return value of GInfo(), you will have to return a data structure. Usually this would be a tuple.
return (Calc, Area)
But your code doesn't assign the return value of GInfo() to anything. Instead, it uses the global declaration to change the value of the global variables. So there shouldn't be an issue here.

Python: exec "function()"

I'm coding a simple test program in python as part of my greater program, but i would l like to pass a sub function name into the main function, so the main function can run the subfunction.
eg:
import datetime;
def cronjob(repeat, interval, task):
if (str(repeat) == 'inf'):
repeat = 99999999999999999999;
position = 0;
interval = datetime.timedelta(seconds=interval);
x = datetime.datetime.now()
while not (position >= repeat):
while (datetime.datetime.now() - x < interval):
pass;
x = datetime.datetime.now();
position += 1;
exec task;
def test():
print "hello";
cronjob(10, 0.1, 'test');
EDIT: Already fixed this, but since nothing is listed here, let me show you how to do it in case someone else needs it.
I fiddled with eval() and exec, and tried just eval(task). that didn't throw an error, so I tried print eval(task) and sure enough, it listed the function's memory address [that is, test()]. finally, I have used eval(task); to then call that function. below is the code fixing this:
import datetime;
def cronjob(repeat, interval, task):
if (str(repeat) == 'inf'):
repeat = 99999999999999999999;
position = 0;
interval = datetime.timedelta(seconds=interval);
x = datetime.datetime.now()
while not (position >= repeat):
while (datetime.datetime.now() - x < interval):
pass;
x = datetime.datetime.now();
position += 1;
eval(task);
def test():
print "hello";
cronjob(10, 0.1, 'test()');
Why not pass the function object itself to the scheduler ?
test is an object and can be used as an argument too!
def test():
print "test"
def exe(func):
func()
exe(test)
I believe since functions are objects, you can just pass one in to the "controlling" function by name, so you don't need the exec call (which is usually used for dynamic code execution).
e.g.
def foo(a_number, a_function):
print a_number
a_number += 1
a_function(a_number)
def bar(another_number):
print another_number
foo(5, bar)
should produce the output:
5
6
In case if you're absolutely sure you want to derive a function from a string, you may want to use a dict as a mapping from strings to functions like follows:
dispatcher = {'dothis': module1.do_this,
'dothat': module2.to_that}
def foo(fun):
fun(arg1, arg2)
def bar(action):
fun = dispatcher.get(action)
if fun:
foo(fun)
This will be much more secure (as action is likely to come from the outside) and provide better decoupling of internal code structure from the external API.

Categories