python function multiple return - python

I would like to transform this code to have a function instead :
variables = ['oki']
for var in variables:
lm_full = sm.formula.ols(formula='%s ~ diag + age + ICVcm3' % var, data=dfwo2).fit()
print("===============================================================================")
print(" formule = %s ~ diag + age + ICVcm3" % var)
print("===============================================================================")
print(lm_full.summary())
At the end I would like something that looks like :
function(oki,diag,age,ICVcm3,dfwo2) that would return the result of the loop.
I have no clue of how to do it. The examples that I found on the internet are very basic.... I don't even know what to type on google to get an answer.

You can return a list of tuples:
def myFunction(variables):
result = []
for var in variables:
formula = " formule = %s ~ diag + age + ICVcm3" % var
lm_full = sm.formula.ols(formula=formula, data=dfwo2).fit()
result.append((formula, lm_full.summary()))
return result

This code shows you how to return the items that have been computed in the function and how to retrieve them in the calling function. Notice how you can return as many, or as few, items as you wish, and that, even if the function returns items your calling code doesn't need you can ignore them. (That's the purpose of the variables named dummy.)
I'm using one of the datasets that comes with statsmodels since I don't recognise the one you're using.
import statsmodels as sm
df = sm.datasets.get_rdataset("Guerry", "HistData").data
df = df[['Lottery', 'Literacy', 'Wealth', 'Region']].dropna()
import statsmodels.formula.api as smf
def regress(variables):
results = [ ]
for variable in variables:
mod = smf.ols(formula='Lottery ~ %s' % variable, data=df)
result = mod.fit()
results . append ( (variable, result.params, result.df_resid, result.rsquared) )
return results
for result in regress (['Literacy', 'Wealth', 'Region']):
variable, dummy, dummy, R_squared = result
print ( variable, R_squared )
Results are like this:
Literacy 0.145720612937
Wealth 0.243180384656
Region 0.142107524677

your loop is var in variables which only contains 1 item: a string.
So what is the purpose of such a loop anyway? diag,age,ICVcm3,dfwo2 where are all these values delcared? What is the function about? Is seems to be some very specific wierd topic.
Though just guessing, something like this could be what you've been looking for:
def myfunction(variables,diag,age,ICVcm3,dfwo2):
for var in variables:
lm_full = sm.formula.ols(formula='%s ~ diag + age + ICVcm3' % var, data=dfwo2).fit()
print("===============================================================================")
print(" formule = %s ~ diag + age + ICVcm3" % var)
print("===============================================================================")
print(lm_full.summary())

Related

When i try to print the mean and standard deviation, I am prompted with a name error: variable not defined

I am trying to print the mean and standard deviation however in its current form it doesnt recognize anything inside the loop. How would I go about correcting this to properly display what is intended. When i try to print the mean it says ex not defined.
import numpy as np
p = 0.44
q = 0.56
mu_1 = 26.5
sigma = 4.3
mu_2 = 76.4
n = 7
print( 'total number of jobs =', n)
lst_times = []
j = 0
def calc_avg_std(n):
while j < 100:
m = np.random.binomial(n,p)
easy_jobs = np.random.normal(mu_1,sigma,m)
n_chall = n-m
chall_jobs = np.random.exponential(mu_2,n_chall)
totalTime = sum(easy_jobs) + sum(chall_jobs)
lst_times.append(totalTime)
j = j + 1
ex = (mu_1 * p) + (mu_2 * q)
ex2 = (p *((mu_1**2)))+ (q*(mu_2**2)*2)
var = ex2-(ex**2)
stdev = np.sqrt(var)
return [ex , stdev]
print(' mean is',ex)
I tried this code without the def and return and runs properly but the professor insists that it should be implemented.
def is used to create a function. When you use return you return the values to the caller.
Replace your last prin witht the following lines:
call the function and keep the return values
print the returned values
mean, stdev = calc_avg_std(n)
print(mean)

Why a float is required?

There is a code:
from arcpy.sa import *
arcpy.CheckOutExtension("Spatial")
print "Creating and defining X and Y coordinates:" #set env properties
env.workspace = r"C:\Users\Desktop\data\new"
env.overwriteOutput = 1
theme = '/watersheds_3D.shp' #polygons in vector format
demName = '/demlab4' # raster of DEM
rasObject = Raster(demName)
my_extent = rasObject.extent #find a grid cell size:
my_cellsize = (rasObject.meanCellHeight + rasObject.meanCellWidth)/2
print my_cellsize
slope_deg = Slope(demName)
slope_deg.save('/demlab4_slope')
for row in arcpy.da.SearchCursor(theme, ["FID","SHAPE#"]): # inside shp file -
print ("Polygon # {}: ".format(row[0]))
for part in row[1]: # Inside the polygon
xCoords = []
yCoords = []
zCoords = []
for pnt in part:
print (" {}, {}, {} ".format(pnt.X, pnt.Y, pnt.Z))
xCoords.append(pnt.X)
yCoords.append(pnt.Y)
zCoords.append(pnt.Z)
area3D = lab4_arcpy_module.define3Darea(my_cellsize, slope_deg)
and function to calculate this:
def define3Darea(my_cellsize, slope_deg):
a = my_cellsize
slope_rad = math.pi * slope_deg / 180 # return in radiant
c = math.sqrt(a**2 + (math.tan(slope_rad)*a)**2)
area3D = a*c
print "Total 3D Area is: ", area3D, "m^2"
return area3D
it gives: TypeError: a float is required.
What can be a problem?
Also need to calculate 3D Area inside the each polygon (4). How t do it?
Not sure what Raster and Slope are doing, but this TypeError: a float is required comes when you try to some float operations on a variable that is not of float type. My guess would be that problem is with : slope_deg variable. See here :
slope_deg = Slope(demName)
slope_deg.save('/demlab4_slope')
You are declaring and doing some operation with slope_deg variable. And now in this statement:
area3D = lab4_arcpy_module.define3Darea(my_cellsize, slope_deg)
you are using same variable which is an instance of Slope class and not a float variable. Either there has to be some attribute of this(Slope) which is float or you have to use correct variable.
i found that theres is some error trying to print loss so:
print ("Model paramters:" )
print ("Weight:%f" %sess.run(W))
print ("bias:%f" %sess.run(b))
#print ("loss:%f" %(loss)) <------
make the error disapear, still don't understand well why is this.

Iterate through list and assign a value to the variable in Python

So i'm currently working on code, which solves simple differentials. For now my code looks something like that:
deff diff():
coeffs = []
#checking a rank of a function
lvl = int(raw_input("Tell me a rank of your function: "))
if lvl == 0:
print "\nIf the rank is 0, a differential of a function will always be 0"
#Asking user to write coefficients (like 4x^2 - he writes 4)
for i in range(0, lvl):
coeff = int(raw_input("Tell me a coefficient: "))
coeffs.append(coeff)
#Printing all coefficients
print "\nSo your coefficients are: "
for item in coeffs:
print item
And so what I want to do next? I have every coefficient in my coeffs[] list. So now I want to take every single one from there and assign it to a different variable, just to make use of it. And how can I do it? I suppose I will have to use loop, but I tried to do so for hours - nothing helped me. Sooo, how can I do this? It would be like : a=coeff[0], b = coeff[1], ..., x = coeff[lvl] .
Just access the coefficients directly from the list via their indices.
If you are wanting to use the values in a different context that entails making changes to the values but you want to keep the original list unchanged then copy the list to a new list,
import copy
mutableCoeffs = copy.copy(coeffs)
You do not need new variables.
You already have all you need to compute the coefficients for the derivative function.
print "Coefficients for the derivative:"
l = len(coeffs) -1
for item in coeffs[:-1]:
print l * item
l -=1
Or if you want to put them in a new list :
deriv_coeffs = []
l = len(coeffs) -1
for item in coeffs[:-1]:
deriv_coeffs.append(l * item)
l -=1
I guess from there you want to differenciate no? So you just assign the cofficient times it rank to the index-1?
deff diff():
coeffs = []
#checking a rank of a function
lvl = int(raw_input("Tell me a rank of your function: "))
if lvl == 0:
print "\nIf the rank is 0, a differential of a function will always be 0"
#Asking user to write coefficients (like 4x^2 - he writes 4)
for i in range(0, lvl):
coeff = int(raw_input("Tell me a coefficient: "))
coeffs.append(coeff)
#Printing all coefficients
print "\nSo your coefficients are: "
for item in coeffs:
print item
answer_coeff = [0]*(lvl-1)
for i in range(0,lvl-1):
answer_coeff[i] = coeff[i+1]*(i+1)
print "The derivative is:"
string_answer = "%d" % answer_coeff[0]
for i in range(1,lvl-1):
string_answer = string_answer + (" + %d * X^%d" % (answer_coeff[i], i))
print string_answer
If you REALLY want to assign a list to variables you could do so by accessing the globals() dict. For example:
for j in len(coeffs):
globals()["elm{0}".format(j)] = coeffs[j]
Then you'll have your coefficients in the global variables elm0, elm1 and so on.
Please note that this is most probably not what you really want (but only what you asked for).

Parsing an equation with custom functions in Python

I have a string that is a mathematical equation, but with some custom functions. I need to find all such functions and replace them with some code.
For example, I have a string:
a+b+f1(f2(x,y),x)
I want code that will replace (say) f2(x,y) with x+y^2 and f1(x,y) with sin(x+y).
It would be ideal if nested functions were supported, like in the example. However, it would still be useful if nesting was not supported.
As I understand from similar topics this can be done using a compiler module like compiler.parse(eq). How I can work with AST object created by compiler.parse(eq) to reconstruct my string back, replacing all found functions?
I need only to perform substitution and then string will be used in other program. Evaluation is not needed.
Here is a minimal working example (+, - , *, /, ** binary and unary operations and function call implemented). The priority of operations are set with parenthesis.
A little bit more than the functionality for the example given is done:
from __future__ import print_function
import ast
def transform(eq,functions):
class EqVisitor(ast.NodeVisitor):
def visit_BinOp(self,node):
#generate("=>BinOp")
generate("(")
self.visit(node.left)
self.visit(node.op)
#generate("ici",str(node.op),node._fields,node._attributes)
#generate(dir(node.op))
self.visit(node.right)
generate(")")
#ast.NodeVisitor.generic_visit(self,node)
def visit_USub(self,node):
generate("-")
def visit_UAdd(self,node):
generate("+")
def visit_Sub(self,node):
generate("-")
def visit_Add(self,node):
generate("+")
def visit_Pow(self,node):
generate("**")
def visit_Mult(self,node):
generate("*")
def visit_Div(self,node):
generate("/")
def visit_Name(self,node):
generate(node.id)
def visit_Call(self,node):
debug("function",node.func.id)
if node.func.id in functions:
debug("defined function")
func_visit(functions[node.func.id],node.args)
return
debug("not defined function",node.func.id)
#generate(node._fields)
#generate("args")
generate(node.func.id)
generate("(")
sep = ""
for arg in node.args:
generate (sep)
self.visit(arg)
sep=","
generate(")")
def visit_Num(self,node):
generate(node.n)
def generic_visit(self, node):
debug ("\n",type(node).__name__)
debug (node._fields)
ast.NodeVisitor.generic_visit(self, node)
def func_visit(definition,concrete_args):
class FuncVisitor(EqVisitor):
def visit_arguments(self,node):
#generate("visit arguments")
#generate(node._fields)
self.arguments={}
for concrete_arg,formal_arg in zip(concrete_args,node.args):
#generate(formal_arg._fields)
self.arguments[formal_arg.id]=concrete_arg
debug(self.arguments)
def visit_Name(self,node):
debug("visit Name",node.id)
if node.id in self.arguments:
eqV.visit(self.arguments[node.id])
else:
generate(node.id)
funcV=FuncVisitor()
funcV.visit(ast.parse(definition))
eqV=EqVisitor()
result = []
def generate(s):
#following line maybe usefull for debug
debug(str(s))
result.append(str(s))
eqV.visit(ast.parse(eq,mode="eval"))
return "".join(result)
def debug(*args,**kwargs):
#print(*args,**kwargs)
pass
Usage:
functions= {
"f1":"def f1(x,y):return x+y**2",
"f2":"def f2(x,y):return sin(x+y)",
}
eq="-(a+b)+f1(f2(+x,y),z)*4/365.12-h"
print(transform(eq,functions))
Result
((-(a+b)+(((sin((+x+y))+(z**2))*4)/365.12))-h)
WARNING
The code works with Python 2.7 and as it is AST dependent is not guaranteed to work with another version of Python. The Python 3 version doesn't work.
The full substitution is quite tricky. Here is my attempt to do it. Here we can successfully inline expressions,
but not in all scenarios. This code works on AST only, made by ast module. And uses codegen to stringify it back to code. The stringifying of ast and modifying ast in general is covered in other SO Q/A: "Parse a .py file, read the AST, modify it, then write back the modified source code".
First we define few helpers:
import ast
import codegen
import copy
def parseExpr(expr):
# Strip:
# Module(body=[Expr(value=
return ast.parse(expr).body[0].value
def toSource(expr):
return codegen.to_source(expr)
After that we define a substitution function using NodeTransformer.
For example:
substitute(parseExpr("a + b"), { "a": parseExpr("1") }) # 1 + b
The simulatenous substitution of multiple variables is needed to properly avoid nasty situations.
For example substituting both a and b for a + b in a + b.
The result should be (a + b) + (a + b), but if we substitute first a for a + b, we'll get (a + b) + b, and then substitute b, we'll get (a + (a + b)) + b which is the wrong result! So simultaneous is important:
class NameTransformer(ast.NodeTransformer):
def __init__(self, names):
self.names = names
def visit_Name(self, node):
if node.id in self.names:
return self.names[node.id]
else:
return node
def substitute(expr, names):
print "substitute"
for varName, varValue in names.iteritems():
print " name " + varName + " for " + toSource(varValue)
print " in " + toSource(expr)
return NameTransformer(names).visit(expr)
Then we write similar NodeTransformer to find calls, where we can inline function definitions:
class CallTransformer(ast.NodeTransformer):
def __init__(self, fnName, varNames, fnExpr):
self.fnName = fnName
self.varNames = varNames
# substitute in new fn expr for each CallTransformer
self.fnExpr = copy.deepcopy(fnExpr)
self.modified = False
def visit_Call(self, node):
if (node.func.id == self.fnName):
if len(node.args) == len(self.varNames):
print "expand call to " + self.fnName + "(" + (", ".join(self.varNames)) + ")" + " with arguments "+ ", ".join(map(toSource, node.args))
# We substitute in args too!
old_node = node
args = map(self.visit, node.args)
names = dict(zip(self.varNames, args))
node = substitute(self.fnExpr, names)
self.modified = True
return node
else:
raise Exception("invalid arity " + toSource(node))
else:
return self.generic_visit(node)
def substituteCalls(expr, definitions, n = 3):
while True:
if (n <= 0):
break
n -= 1
modified = False
for fnName, varNames, fnExpr in definitions:
transformer = CallTransformer(fnName, varNames, fnExpr)
expr = transformer.visit(expr)
modified = modified or transformer.modified
if not modified:
break
return expr
The substituteCalls is recursive so we can inline recursive functions too. Also there is an explicit limit, because some definitions might be infinitely recursive (as fact below). There is a bit of ugly looking copying, but it is required to separate different subtrees.
And the example code:
if True:
print "f1 first, unique variable names"
ex = parseExpr("a+b+f1(f2(x, y), x)")
ex = substituteCalls(ex, [
("f1", ["u", "v"], parseExpr("sin(u + v)")),
("f2", ["i", "j"], parseExpr("i + j ^ 2"))])
print toSource(ex)
print "---"
if True:
print "f1 first"
ex = parseExpr("a+b+f1(f2(x, y), x)")
ex = substituteCalls(ex, [
("f1", ["x", "y"], parseExpr("sin(x + y)")),
("f2", ["x", "y"], parseExpr("x + y ^ 2"))])
print toSource(ex)
print "---"
if True:
print "f2 first"
ex = parseExpr("f1(f1(x, x), y)")
ex = substituteCalls(ex, [
("f1", ["x", "y"], parseExpr("x + y"))])
print toSource(ex)
print "---"
if True:
print "fact"
ex = parseExpr("fact(n)")
ex = substituteCalls(ex, [
("fact", ["n"], parseExpr("n if n == 0 else n * fact(n-1)"))])
print toSource(ex)
print "---"
Which prints out:
f1 first, unique variable names
expand call to f1(u, v) with arguments f2(x, y), x
substitute
name u for f2(x, y)
name v for x
in sin((u + v))
expand call to f2(i, j) with arguments x, y
substitute
name i for x
name j for y
in ((i + j) ^ 2)
((a + b) + sin((((x + y) ^ 2) + x)))
---
f1 first
expand call to f1(x, y) with arguments f2(x, y), x
substitute
name y for x
name x for f2(x, y)
in sin((x + y))
expand call to f2(x, y) with arguments x, y
substitute
name y for y
name x for x
in ((x + y) ^ 2)
((a + b) + sin((((x + y) ^ 2) + x)))
---
f2 first
expand call to f1(x, y) with arguments f1(x, x), y
expand call to f1(x, y) with arguments x, x
substitute
name y for x
name x for x
in (x + y)
substitute
name y for y
name x for (x + x)
in (x + x)
((x + x) + ((x + x) + x))
---
fact
expand call to fact(n) with arguments n
substitute
name n for n
in n if (n == 0) else (n * fact((n - 1)))
expand call to fact(n) with arguments (n - 1)
substitute
name n for (n - 1)
in n if (n == 0) else (n * fact((n - 1)))
expand call to fact(n) with arguments ((n - 1) - 1)
substitute
name n for ((n - 1) - 1)
in n if (n == 0) else (n * fact((n - 1)))
n if (n == 0) else (n * (n - 1) if ((n - 1) == 0) else ((n - 1) * ((n - 1) - 1) if (((n - 1) - 1) == 0) else (((n - 1) - 1) * fact((((n - 1) - 1) - 1)))))
Unfortunately codegen version in pypi is buggy. It doesn't parenthesise expressions properly, even AST says they should. I used jbremer/codegen (pip install git+git://github.com/jbremer/codegen). It adds unnecessary parenthesis too, but it's better than no at all. Thanks to #XavierCombelle for the tip.
The substitution gets trickier if you have anonymous functions, i.e lambda. Then you need to rename variables. You could try to search for lambda calculus with substitution or implementation. Yet I had bad luck to find any articles which use Python for the task.
Do you know the variables beforehand?
I recommend using SymPy!
Take for example the following:
import sympy
a,b,x,y = sympy.symbols('a b x y')
f1 = sympy.Function('f1')
f2 = sympy.Function('f2')
readString = "a+b+f1(f2(x,y),x)"
z = eval(readString)
'z' will now be a symbolic term representing the mathematical formula. You can print it out. You can then use subs to replace symbolic terms or functions. You can either represent sine symbolically again (like f1 and f2) or you can possibly use the sin() in sympy.mpmath.
Depending on your needs, this approach is great because you can eventually compute, evaluate or simplify this expression.
What is your long term goal? Is it to evaluate the function or simply perform substitution? In the former case you can simply try this (note that f1 and f2 could also be dynamically defined):
import math
math.sin
def f2(x, y):
return x + y ** 2
def f1(x, y):
return math.sin(x + y)
a, b = 1, 2
x, y = 3, 4
eval('a + b + f1(f2(x, y), x)')
# 2.991148690709596
If you want to replace the functions and get back the modified version, you will indeed have to resort to some sort of AST parser. Be careful though with the use of eval, as this opens up a security hole for malicious user input code.
(Using sympy as adrianX suggested, with some extra code.)
Code below converts a given string to a new string after combining given functions. It's hasty and poorly documented, but it works.
WARNING!
Contains exec eval, malicious code could probably have an effected, if input is provided by external users.
UPDATE:
Rewrote the whole code. Works in Python 2.7.
Function arguments can be separated by comma or whitespace or both.
All examples in question and comments are working.
import re
import sympy
##################################################
# Input string and functions
initial_str = 'a1+myf1(myf2(a, b),y)'
given_functions = {'myf1(x,y)': 'cross(x,y)', 'myf2(a, b)': 'value(a,b)'}
##################################################
print '\nEXECUTED/EVALUATED STUFF:\n'
processed_str = initial_str
def fixed_power_op(str_to_fix):
return str_to_fix.replace('^', '**')
def fixed_multiplication(str_to_fix):
"""
Inserts multiplication symbol wherever omitted.
"""
pattern_digit_x = r"(\d)([A-Za-z])" # 4x -> 4*x
pattern_par_digit = r"(\))(\d)" # )4 -> )*4
pattern_digit_par = r"[^a-zA-Z]?_?(\d)(\()" # 4( -> 4*(
for patt in (pattern_digit_x, pattern_par_digit, pattern_digit_par):
str_to_fix = re.sub(patt, r'\1*\2', str_to_fix)
return str_to_fix
processed_str = fixed_power_op(processed_str)
class FProcessing(object):
def __init__(self, func_key, func_body):
self.func_key = func_key
self.func_body = func_body
def sliced_func_name(self):
return re.sub(r'(.+)\(.+', r'\1', self.func_key)
def sliced_func_args(self):
return re.search(r'\((.*)\)', self.func_key).group()
def sliced_args(self):
"""
Returns arguments found for given function. Arguments can be separated by comma or whitespace.
:returns (list)
"""
if ',' in self.sliced_func_args():
arg_separator = ','
else:
arg_separator = ' '
return self.sliced_func_args().replace('(', '').replace(')', '').split(arg_separator)
def num_of_sliced_args(self):
"""
Returns number of arguments found for given function.
"""
return len(self.sliced_args())
def functions_in_function_body(self):
"""
Detects functions in function body.
e.g. f1(x,y): sin(x+y**2), will result in "sin"
:returns (set)
"""
return set(re.findall(r'([a-zA-Z]+_?\w*)\(', self.func_body))
def symbols_in_func_body(self):
"""
Detects non argument symbols in function body.
"""
symbols_in_body = set(re.findall(r'[a-zA-Z]+_\w*', self.func_body))
return symbols_in_body - self.functions_in_function_body()
# --------------------------------------------------------------------------------------
# SYMBOL DETECTION (x, y, z, mz,..)
# Prohibited symbols
prohibited_symbol_names = set()
# Custom function names are prohibited symbol names.
for key in given_functions.keys():
prohibited_symbol_names |= {FProcessing(func_key=key, func_body=None).sliced_func_name()}
def symbols_in_str(provided_str):
"""
Returns a set of symbol names that are contained in provided string.
Allowed symbols start with a letter followed by 0 or more letters,
and then 0 or more numbers (eg. x, x1, Na, Xaa_sd, xa123)
"""
symbol_pattern = re.compile(r'[A-Za-z]+\d*')
symbol_name_set = re.findall(symbol_pattern, provided_str)
# Filters out prohibited.
symbol_name_set = {i for i in symbol_name_set if (i not in prohibited_symbol_names)}
return symbol_name_set
# ----------------------------------------------------------------
# EXEC SYMBOLS
symbols_in_given_str = symbols_in_str(initial_str)
# e.g. " x, y, sd = sympy.symbols('x y sd') "
symbol_string_to_exec = ', '.join(symbols_in_given_str)
symbol_string_to_exec += ' = '
symbol_string_to_exec += "sympy.symbols('%s')" % ' '.join(symbols_in_given_str)
exec symbol_string_to_exec
# -----------------------------------------------------------------------------------------
# FUNCTIONS
# Detects secondary functions (functions contained in body of given_functions dict)
sec_functions = set()
for key, val in given_functions.items():
sec_functions |= FProcessing(func_key=key, func_body=val).functions_in_function_body()
def secondary_function_as_exec_str(func_key):
"""
Used for functions that are contained in the function body of given_functions.
E.g. given_functions = {f1(x): sin(4+x)}
"my_f1 = sympy.Function('sin')(x)"
:param func_key: (str)
:return: (str)
"""
returned_str = "%s = sympy.Function('%s')" % (func_key, func_key)
print returned_str
return returned_str
def given_function_as_sympy_class_as_str(func_key, func_body):
"""
Converts given_function to sympy class and executes it.
E.g. class f1(sympy.Function):
nargs = (1, 2)
#classmethod
def eval(cls, x, y):
return cross(x+y**2)
:param func_key: (str)
:return: (None)
"""
func_proc_instance = FProcessing(func_key=func_key, func_body=func_body)
returned_str = 'class %s(sympy.Function): ' % func_proc_instance.sliced_func_name()
returned_str += '\n\tnargs = %s' % func_proc_instance.num_of_sliced_args()
returned_str += '\n\t#classmethod'
returned_str += '\n\tdef eval(cls, %s):' % ','.join(func_proc_instance.sliced_args())
returned_str = returned_str.replace("'", '')
returned_str += '\n\t\treturn %s' % func_body
returned_str = fixed_power_op(returned_str)
print '\n', returned_str
return returned_str
# Executes functions in given_functions' body
for name in sec_functions:
exec secondary_function_as_exec_str(func_key=name)
# Executes given_functions
for key, val in given_functions.items():
exec given_function_as_sympy_class_as_str(func_key=key, func_body=val)
final_result = eval(initial_str)
# PRINTING
print '\n' + ('-'*40)
print '\nRESULTS'
print '\nInitial string: \n%s' % initial_str
print '\nGiven functions:'
for key, val in given_functions.iteritems():
print '%s: ' % key, val
print '\nResult: \n%s' % final_result
I think you want to use something like PyBison which is a parser generator.
See an example that contains the basic code you need here:
http://freenet.mcnabhosting.com/python/pybison/calc.py
You need to add a token type for functions, and a rule for functions, and then what happens with that function if it is encountered.
If you need other information about parsing and so on, try to read some basic tutorials on Lex and (Yacc or Bison).

Returning multiple integers as separate variables

I am trying to make a program that grabs 5 integers from the user, and then finds the average of them. I have it set up to take in the 5 numbers, but how do I return them all as separate variables so I can use them later on? Thanks!
def main():
x = 0
testScoreNumber = 1
while x < 5:
getNumber_0_100(testScoreNumber)
x += 1
testScoreNumber += 1
calcAverage(score1, score2, score3, score4, score5)
print(calculatedAverage)
def getNumber_0_100(testnumber):
test = int(input("Enter test score " + str(testnumber) + ":"))
testcount = 0
while testcount < 1:
test = int(input("Enter test score " + str(testnumber) + ":"))
if test > 0 or test < 100:
testcount += 1
return test
^Here is the problem, the everytime this function runs, I want it to return a different value to a different variable. Ex. test1, test2, test3.
def calcAverage(_score1,_score2,_score3,_score4,_score5):
total = _score1 + _score2 + _score3 + _score4 + _score5
calculatedAverage = total/5
return calculatedAverage
You need to store the result somewhere. It is usually (always?) a bad idea to dynamically create variable names (although it is possible using globals). The typical place to store the results is in a list or a dictionary -- in this case, I'd use a list.
change this portion of the code:
x = 0
testScoreNumber = 1
while x < 5:
getNumber_0_100(testScoreNumber)
x += 1
testScoreNumber += 1
to:
results = []
for x in range(5):
results.append( getNumber_0_100(x+1) )
which can be condensed even further:
results = [ getNumber_0_100(x+1) for x in range(5) ]
You can then pass that results list to your next function:
avg = get_ave(results[0],results[1],...)
print(avg)
Or, you can use the unpacking operator for shorthand:
avg = get_ave(*results)
print(avg)
It isn't the responsibility of the returning function to say what the caller does with its return value. In your case, it would be simple to let main have a list where it adds the return values. You could do this:
scores = []
for i in range(5):
scores.append(getNumber_0_100(i))
calcAverage(*scores)
Note that *scores is to pass a list as arguments to your calcAverage function. It's probably better to have calculateAverage be a general function which takes a list of values and calculates their average (i.e. doesn't just work on five numbers):
def calcAverage(numbers):
return sum(numbers) / len(numbers)
Then you'd call it with just calcAverage(scores)
A more Pythonic way to write the first part might be scores = [getNumber_0_100(i) for i in range(5)]
Python allows you to return a tuple, and you can unroll this tuple when you receive the return values. For example:
def return_multiple():
# do something to calculate test1, test2, and test3
return (test1, test2, test3)
val1, val2, val3 = return_multiple()
The limitation here though is that you need to know how many variables you're returning. If the number of inputs is variable, you're better off using lists.

Categories