Get entire function as string / and transform string into function? - python

I want to get an entire Python function and save it as string (for instance, Javascript can simply do functionString = functionVar.toString().
Example:
#I defined a function with a body:
def someFunction(hey):
return hey + hey + hey
I want to convert this function to string and get exactly the same text as I typed above (without the comment, of course)
Then I want to do the inverse operation: from the string, convert it to a function and and store it in a variable to be called.

Using exec you can almost get what you're asking. Encoding the function as a string is the easy part.
"""Encode the function as a string"""
import inspect
funcString = inspect.getsource(someFunction)
Retrieving the function from the string is a touch more work. The following approach will have issues with globals or other variables outside the scope of the function you're trying to recover, but if the source completely specifies it then the following idea should work.
d = {}
exec(funcString, d)
f = next(d[k] for k in d if k != '__builtins__')
After running, the code defined by the source used to generate f in the first place will be bound to the variable f.

Related

How to convert a string to an integer class within a python function?

In a python function, I have defined two variables as letters.
def Vandermonde(x, d):
x_0=-1
a = np.arange(d)
I am getting the error that "d"is not defined in a = np.arange(d). I suspect, but could be wrong, that this is because d is classified as a string not an integer.
I was expecting this to not matter in the code of the function where d is a variable. I know the code works (the rest of the code not shown does work on its own where d is defined as an integer before hand.
How do I get the error message to not appear when defining this as a function?
Indentation! Python functions (and their respective scopes) are defined via indentations.
def Vandermonde(x, d):
x_0=-1
a = np.arange(d) # Note the indentation here
should fix the problem...

Passing Python variable to JavaScript

I am trying to execute some JavaScript code through Python.
def home():
code = """
var regexp = new RegExp(/playerCaptionsTracklistRenderer.*?(youtube.com\/api\/timedtext.*?)"/);
var url = regexp.exec(document.body.innerHTML)[1];
open("caption.py?url=" + encodeURIComponent(url));
"""
code = quote(code, safe='~()*!.\'')
return """YouTube Transcriber"""
As I understand, variables from Python must be passing to JavaScript automatically, but I get the following exception in last line in JavaScript:
Uncaught ReferenceError: code is not defined
You aren't telling python to put the contents of code into your returned string. You could do it like this:
return """YouTube Transcriber"""
You can't just put a variable name in a string and expect its contents to be automatically put into the string. It's not clear why you would expect that to happen. It's something you explicitly have to do, via either string formatting, or concatenation.
Inside your return statement, inside the JS function, there is literally the word "code", which is undefined. You probably wanted to enter the value of the variable code in which case you need to break the string apart, and add the code variable in between like this:
return """YouTube Transcriber"""

If strings in Python are immutable, why can I change a string in a function?

I'm new to Python, and I'm writing a function to change the case of all characters in a string. The function itself is called swapCases(), and I'm using the library function swapcase() within my own function. Here is the code that I use to test my function:
print(swapCases("HoLa"))
In the first case, my function reads:
def swapCases(s):
for i in range(len(s)):
s[i] = s[i].swapcase()
return s
When I run this code, I get a message from the compiler: "str object does not support item assignment." I Googled the message and it said that strings in Python are immutable and therefore can't be changed. However, when I change my function to this:
def swapCases(s):
s = s.swapcase()
return s
the function does exactly what I want, and the test prints out "hOlA." If strings are immutable in Python, why does this work? Doesn't being immutable mean that I can't change them?
By assigning it to the variable s, you are reassigning s. This gets rid of the reference to the old string "HoLa" and replaces it with a reference to the string returned from s.swapcases()
In your original case, you are attempting to modify the string index by index. Doing this would be mutating the existing references, which is not allowed. This is what is meant by immutable.
Your function is not modifying a string object. It's modifying a name assigned to it. When you assign directly, like this,
s = "abc"
s[2] = "z"
...you are saying "change the third character in this particular string object to 'z'." On the other hand, if you assign twice, like this,
s = "abc"
s = "abz"
...you are saying "change the name, s, to refer to a new string object." This applies whether it's created as a local variable (as above) or as a function argument.

python imported module dot notation as function parameter input

New to python programming here. I need some help understand why this does not work:
import x.y # x is a package with __init__.py
def func1(x.y.z): # I get a syntax error here
It works when I do this:
import x.y
a = x.y.z
def func1(a):
I've search the web and can't find anything that would answer this somewhat directly.
Thanks.
With def you define new functions which accept some possibly unknown(!) arguments.
So, def sin(x): means "define a function called sin that accepts one argument". Note that this code means that x can be absolutely anything, the function definition doesn't (and cannot) apply any restrictions on its type, value, size, etc.
When you do
a = "hello"
def test(a):
pass
The a in the function definition is merely an argument that doesn't have any relation to any other a you use in your code! You could've called it x, pi, z or whatever as the name doesn't really matter (code readability aside).
When you try to write
def test(x.y.z):
pass
You get a syntax error as there exist restrictions on the variables' and arguments' names that don't allow you to call a variable any name you want. Why? Simply because otherwise you'll get a lot of uncertainty. For example, how to parse this:
# a poorly formatted number literal or a variable definition??
1234hello = "test"
# attempt to access a member of a class (or module) or a variable definition??
x.y.z = 5
# is "yay a variable's name or a poorly formatted string literal??
x = "yay - 5
# the same question as above
f' = df/dx
A function argument is a variable, so the very same restrictions are imposed on it as well.
BTW, take a look at the SO code highlighter going nuts trying to highlight the code above.

Alternative to exec

I'm currently trying to code a Python (3.4.4) GUI with tkinter which should allow to fit an arbitrary function to some datapoints. To start easy, I'd like to create some input-function and evaluate it. Later, I would like to plot and fit it using curve_fit from scipy.
In order to do so, I would like to create a dynamic (fitting) function from a user-input-string. I found and read about exec, but people say that (1) it is not safe to use and (2) there is always a better alternative (e.g. here and in many other places). So, I was wondering what would be the alternative in this case?
Here is some example code with two nested functions which works but it's not dynamic:
def buttonfit_press():
def f(x):
return x+1
return f
print(buttonfit_press()(4))
And here is some code that gives rise to NameError: name 'f' is not defined before I can even start to use xval:
def buttonfit_press2(xval):
actfitfunc = "f(x)=x+1"
execstr = "def {}:\n return {}\n".format(actfitfunc.split("=")[0], actfitfunc.split("=")[1])
exec(execstr)
return f
print(buttonfit_press2(4))
An alternative approach with types.FunctionType discussed here (10303248) wasn't successful either...
So, my question is: Is there a good alternative I could use for this scenario? Or if not, how can I make the code with exec run?
I hope it's understandable and not too vague. Thanks in advance for your ideas and input.
#Gábor Erdős:
Either I don't understand or I disagree. If I code the same segment in the mainloop, it recognizes f and I can execute the code segment from execstr:
actfitfunc = "f(x)=x+1"
execstr = "def {}:\n return {}\n".format(actfitfunc.split("=")[0], actfitfunc.split("=")[1])
exec(execstr)
print(f(4))
>>> 5
#Łukasz Rogalski:
Printing execstr seems fine to me:
def f(x):
return x+1
Indentation error is unlikely due to my editor, but I double-checked - it's fine.
Introducing my_locals, calling it in exec and printing in afterwards shows:
{'f': <function f at 0x000000000348D8C8>}
However, I still get NameError: name 'f' is not defined.
#user3691475:
Your example is very similar to my first example. But this is not "dynamic" in my understanding, i.e. one can not change the output of the function while the code is running.
#Dunes:
I think this is going in the right direction, thanks. However, I don't understand yet how I can evaluate and use this function in the next step? What I mean is: in order to be able to fit it, I have to extract fitting variables (i.e. a in f(x)=a*x+b) or evaluate the function at various x-values (i.e. print(f(3.14))).
The problem with exec/eval, is that they can execute arbitrary code. So to use exec or eval you need to either carefully parse the code fragment to ensure it doesn't contain malicious code (an incredibly hard task), or be sure that the source of the code can be trusted. If you're making a small program for personal use then that's fine. A big program that's responsible for sensitive data or money, definitely not. It would seem your use case counts as having a trusted source.
If all you want is to create an arbitrary function at runtime, then just use a combination of the lambda expression and eval. eg.
func_str = "lambda x: x + 1" # equates to f(x)=x+1
func = eval(func_str)
assert func(4) == 5
The reason why your attempt isn't working is that locals(), in the context of a function, creates a copy of the local namespace. Mutations to the resulting dictionary do not effect the current local namespace. You would need to do something like:
def g():
src = """
def f(x):
return x + 1
"""
exec_namespace = {} # exec will place the function f in this dictionary
exec(src, exec_namespace)
return exec_namespace['f'] # retrieve f
I'm not sure what exactly are you trying to do, i.e. what functions are allowed, what operations are permitted, etc.
Here is an example of a function generator with one dynamic parameter:
>>> def generator(n):
def f(x):
return x+n
return f
>>> plus_one=generator(1)
>>> print(plus_one(4))
5

Categories