Call a function with dynamic paramter - python

If I had a function name stored in a variable, how can I know inside the function the name of the variable used to call it?
e.g.:
var_name = function1
var_name("3")
def function1(self, params=""):
print("the parameter is " + params + "called by" + VARIABLENAME)
I would have an output like:
the paramter is 3 called by var_name
Thanks for the support

Unfortunately you can't do that on python, but you could do something like this to get the current function:
import inspect
def function1(n):
print("the parameter is " + n + " called by " + inspect.getframeinfo(inspect.currentframe()).function)
function1("3")

You could identify the calling function and additionally lookup all defined functions using globals():
import inspect
import types
def function1(n):
alias = getCallingAliases(inspect.getframeinfo(inspect.currentframe()).function)
print("the parameter is " + n + " called by " + alias)
def getCallingAliases(realFn):
for k, v in globals().items():
if isinstance(v, types.FunctionType):
# k == function or alias
# v == original function
aliasName = v.__name__
if realFn != k and realFn == aliasName:
return k
return '<unknown>'
var_name = function1
var_name("3")
Out:
the parameter is 3 called by var_name
Note: That's not error prone and might need to be adjusted to your needs (regarding classes, imported function from other modules, ...)

Related

Problem using exec within class' function in Python

The following code works as expected
name = "Test"
myname = ""
exec('myname ="' + name + '"')
print(myname)
Which shows as result:
Test
Problem
However, if I define the same within a function in a class and execute it I get as result an empty string.
class new(object):
def __init__(self, name):
self.print(name)
def print(self, name):
myname = ""
exec('myname ="' + name + '"')
print(myname)
a = new("My name")
The above is a toy example code of a bigger code.
Question
How to define the function so as to get the same result? The exec function is actually needed in the bigger code.
You can pass a dictionary as the globals (or locals) for exec.
def print(self, name):
d = {"myname": ""}
exec('myname ="' + name + '"', d)
print(d["myname"])

Multiple functions with optional arguments causes the arguments to get lost on the stack

The following code:
def func_3(some_number, other_number=1):
print("func_3 " + str(other_number))
return other_number
def func_2(some_number, other_number=1):
print("func_2 " + str(other_number))
return func_3(some_number, other_number=1)
def func_1(some_number, other_number=1):
print("func_1 " + str(other_number))
return func_2(some_number, other_number=1)
def func_0(some_number, other_number=1):
print("func_0 " + str(other_number))
return func_1(some_number, other_number=1)
func_0(123456, 2)
will generate the following output:
func_0 2
func_1 1
func_2 1
func_3 1
Why does this occur?
Besides func_0, you're explicitly passing in 1 for the other_number parameter. If you want to pass in 2, rather than 1, change the return statements so that they explicitly pass in other_number as a parameter.
For example, use:
return func_1(some_number, other_number=other_number)
rather than:
return func_1(some_number, other_number=1)

How to chain Python function calls so the behaviour is as follows

I stumbled upon the following problem on a python challenge: Write a function that satisfies the following rule for any number of function calls.
f()()()()()(s) == 'fooooo' + s;
example:
f('it') == 'fit';
f()('x') == 'fox';
f()()('bar') == 'foobar';
f()()()('l') == 'foool';
The function should be stateless and should not use any variables outside the scope.
The function signature was:
def f(s=None):
# Your code here
I thought that in order to be able to chain multiple calls we will have to return a function when no string is passed into the function, but can't figure out how to build the expected string with no external variables. Suggestions?
def f(s=None):
if s is None:
# concatenate an 'o'?
return f
else:
# Last call, return the result str.
return s
An alternative to Nikola's answer is something like this:
def f(s=None):
if s: return f'f{s}'
def factory(prefix):
def inner(s=None):
return f'f{prefix}{s}' if s else factory(prefix + 'o')
return inner
return factory('o')
using a closure and no helper function.
Obviously, you need to store the number of 'o' somewhere in the memory (e.g. the code) of f. To achieve this, you can benefit from these 2 features of Python:
You can define functions inside other functions
There's this thing called argument binding which allows you to tell Python to fix the some or all of the arguments of your function. This is done through functools.partial
And here's the solution
from functools import partial
def f(s=None):
# Define a new function g which takes the current text and takes s
def g(current_text, s=None):
if s is not None:
return current_text + s
else:
# If called with an empty argument, just rebind current_text with an extra o
return partial(g, current_text + "o")
# Just call g with the initial conditions
return g("f", s)
print(f()()()()()("s")) # fooooos
print(f("s")) # fs
You can try this:
def f(s=None):
string = "f"
def ret(p=None):
nonlocal string
string += "o"
return ret if not p else string + p
return ret if not s else string + s
This is my go at it:
def f(x=None, seq=''):
if x:
return 'f' + seq + x
else:
def g(y=None, p=seq + 'o'):
return f(y, p)
return g
Edit If you really need the function signature to be f(x=None), use this:
def f(x=None):
def f_(x=None, seq=''):
if x:
return 'f' + seq + x
else:
def g(y=None, p=seq + 'o'):
return f_(y, p)
return g
return f_(x)
:^)
Just for printing the string:
def f(s=None):
def fo(s=None):
if s==None:
print('o',end='')
return fo
else:
print(s)
return
if s!=None:
print('f',end='')
print(s)
return
elif s==None:
print('fo',end='')
return fo
Cute problem. This is a compact way to do it:
def f(s=None, prefix="f"):
if s: return prefix + s
return lambda s=None: f(s, prefix=prefix+"o")
FP:
f=lambda s=None,prefix='f':prefix+s if s else lambda s=None,prefix=prefix+'o':f(s,prefix)

NameError: name 'getTempo' is not defined

i'm getting an error defining function "getTempo" and i don't know why... Thanks for the help.
example:
L=[Musica("aerossol",4.9),Musica("lua",5.3),Musica("monte",3.2),Musica("rita",4.7)];getTempo("lua",L)
should give:
lua:5.3
5.3
class Musica:
def __init__(self,nome,tempo):
self.nome=nome
self.tempo=tempo
def __repr__(self):
return self.nome+":"+str(self.tempo)
def getTempo(nomeMusica,ListaMusicas):
if ListaMusicas==[]:
print ("Inexistente")
else:
meio=len(ListaMusicas)//2
print (ListaMusicas[meio])
A = [i[0] for i in ListaMusicas]
B = [i[1] for i in ListaMusicas]
if nomeMusica==A[meio]:
print (B[meio])
elif nomeMusica<A[meio]:
return getTempo(nomeMusica,ListaMusicas[:meio])
else:
return getTempo(nomeMusica,ListaMusicas[(meio+1):])
In python, unlike languages like Java or C++, instance attributes and methods must be accessed on the instance, so you must write self.getTempo in order for getTempo to resolve.
EDIT - Selective Reading Failure
You also need to make sure that all method definitions include an argument for the class instance itself, which will be the first argument passed. By convention, this is the self argument, but it can be any name you choose. Here is the modified function definition:
def getTempo(self, nomeMusica,ListaMusicas): # Changed
if ListaMusicas==[]:
print ("Inexistente")
else:
meio=len(ListaMusicas)//2
print (ListaMusicas[meio])
A = [i[0] for i in ListaMusicas]
B = [i[1] for i in ListaMusicas]
if nomeMusica==A[meio]:
print (B[meio])
elif nomeMusica<A[meio]:
return self.getTempo(nomeMusica,ListaMusicas[:meio]) # Changed
else:
return self.getTempo(nomeMusica,ListaMusicas[(meio+1):]) # Changed

Dynamically creating nested functions from a yaml script

I have a yaml script that we use to specify functions. The yaml file parses into a dictionary (actually, nested dictionaries) that I want to use to construct the functions described in this yaml file. Here's an example yaml entry:
Resistance:
arguments:
voltage: "V"
current: "A"
parameters:
a: -1.23
b: 0.772
format: "{a}*voltage+{b}*current+f(voltage)"
subfunctions:
f:
arguments:
voltage: "V"
parameters:
a: -6.32
format: "exp({a}*voltage)"
Now, what need to do is parse this file and then build up the namespaces so that at the end, I can bind a variable called "Resistance" to a closure or lambda that reflects the above function (with nested "f" subfunction).
My strategy was to go "bottom up" using a recursive algorithm. Here is my code:
def evaluateSimpleFunction(entry):
functionString = entry['format']
functionArgs = []
Params = []
if "arguments" in entry and entry["arguments"] != None:
functionArgs = entry['arguments'].keys()
if "parameters" in entry and entry["parameters"] != None:
Params = entry['parameters']
formatString = ""
for param in Params:
formatString += str(param)+"="+str(Params[param])+","
functionString = eval("functionString.format("+formatString+")")
lambdaString = ""
for arg in functionArgs:
lambdaString += str(arg)+","
return eval("lambda " + lambdaString + ":" + functionString)
def recursiveLoader(entry):
if "subfunctions" in entry:
subfunctions = entry['subfunctions']
bindingString = ""
for subFunc in subfunctions:
bindingString +=str(subFunc)+"=[];"
exec(bindingString)
for subFunc in subfunctions:
exec(str(subFunc)+"= recursiveLoader(subfunctions[subFunc])")
return lambda : evaluateSimpleFunction(entry)
else:
return lambda : evaluateSimpleFunction(entry)
import yaml,os, math
os.chdir(r"C:\Users\212544808\Desktop\PySim\xferdb")
keyFields = ["Resistance","OCV"]
containerKeys = ["_internalResistance","_OCV"]
functionContainer = {}
with open("LGJP1.yml",'r') as modelFile:
parsedModelFile = yaml.load(modelFile)
#for funcKey,containerKey in zip(keyFields,containerKeys):
entry = parsedModelFile["capacityDegrade"]
g = recursiveLoader(entry)
Now, as it stands, I get an error because I am using unqualified exec with a nested function.
However, I don't want to resort to globals, because I will use this process for multiple functions and will therefore overwrite any globals I use.
I'm hoping for suggestions on how to construct nested functions algorithmically from an external config file like the yaml file - exec doesn't seem to be the way to go.
BTW: I'm using Python 2.7
UPPDATE
Another, more robust option may be to use a global class instance to create a namespace for each function. For example:
class Namespace(): pass
namespace_1 = Namespace()
#assume that the function "exponent" has arguments X, Y and body "Q(X*Y)",
#where "Q" has body "x**2+3*y"
exec("namespace_1.exponent = lambda X,Y: Q(X*Y)")
exec("namespace_1.Q = lambda x,y: x**2+3*y")
The benefit of this approach is that I can then loop through the members of the class for a particular function to create a single source code string that I can pass to "eval" to get the final function.
I'm doing all of this because I have not found a reliable way to create nested closures using eval and exec.
Here's a simplified example of what I mean using your input. I have hardcoded it, but you could easily build up a similar module file using your parser:
def makeModule(**kwargs):
print repr(kwargs)
module_filename = 'generated_module.py'
with open(module_filename, 'w') as module_file:
module_file.write('''\
from math import *
def func(voltage, current):
def f(voltage):
return exp({a1} * voltage)
return {a0}*voltage+{b}*current+f(voltage)
'''.format(**kwargs))
module_name = module_filename.replace('.py', '')
module = __import__(module_name)
return module.func
def main():
func = makeModule(a0=-1.23, b=0.772, a1=-6.32)
print 'Result:', func(2, 3)
if __name__ == '__main__':
main()
It works by generating a file called generated_module.py and then using the builtin function __import__ to import it as a module that is stored into the variable module. Like any other module, then you can access the names defined in it, namely func.

Categories

Resources