Consider a String a f-string in Python - python

Suppose I have
x = 3
s = "f'12{x}4'"
How to consider s as f-string to print 1234, like writing print(f'12{x}4')
when I print s, it prints it as it as: f'12{x}4'

Remve the double quotations that should fix the issue because the f in a f string needs to be outside the actuall string

You are missing two concepts.
The first one, is how you tell python your string is an f-string. The way to do this, is by adding the character 'f' before the first quotation mark:
f"this will be a f-string"
Whatever you have between {}, it will be a previously defined variable:
x = "something"
f"this will be {x}"

Assuming you ask this because you can not use actual f-strings, but also don't want to pass the parameters explicitly using format, maybe because you do not know which parameter are in the not-really-an-f-string, and also assuming you don't want to use eval, because, well, eval.
You could pass the variables in the locals or globals scope to format:
>>> x = 3
>>> s = '12{x}4'
>>> s.format(**globals())
'1234'
>>> s.format(**locals())
'1234'
Depending on where s is coming from (user input perhaps?) This might still be a bit risky, though, and it might be better to define a dict of "allowed" variables and use that in format. As with globals and locals, any unused variables do not matter.
>>> vars = {"x": x, "y": y, "z": z}
>>> s.format(**vars)
Note that this does not give you the full power of f-strings, though, which will also evaluate expressions. For instance, the above will not work for s = '12{x*x}4'.

You'd do this -
x = 3
s = f'12{x}4'

This can also work.
x = 3
s = "12{}4"
print(s.format(x))

Just remove extra commas
s = f'12{x}4'

x = 3
s = '12{}4'.format(x)
or
x = 3
print('12%s4' %x)

Related

How should a variable be passed within format() in Python?

I am seeking to be able to use variables within the format() parentheses, in order to parameterize it within a function. Providing an example below:
sample_str = 'sample_str_{nvars}'
nvars_test = 'apple'
sample_str.format(nvars = nvars_test) #Successful Result: ''sample_str_apple''
But the following does not work -
sample_str = 'sample_str_{nvars}'
nvars_test_2 = 'nvars = apple'
sample_str.format(nvars_test_2) # KeyError: 'nvars'
Would anyone know how to do this? Thanks.
Many thanks for guidance. I did a bit more searching. For anyone who may run into the same problem, please see examples here: https://pyformat.info
sample_str = 'sample_str_{nvars}'
nvars_test_2 = {'nvars':'apple'}
sample_str.format(**nvars_test_2) #Successful Result: ''sample_str_apple''
First, I'd recommend checking out the string format examples.
Your first example works as expected. From the documentation, you are permitted to actually name the thing you are passing into {}, and then pass in a same-named variable for str.format():
'Coordinates: {latitude}, {longitude}'.format(latitude='37.24N', longitude='-115.81W')
# returns 'Coordinates: 37.24N, -115.81W'
Your second example doesn't work because you are not passing a variable called nvars in with str.format() - you are passing in a string: 'nvars = apple'.
sample_str = 'sample_str_{nvars}'
nvars_test_2 = 'nvars = apple'
sample_str.format(nvars_test_2) # KeyError: 'nvars'
It's a little more common (I think) to not name those curly-braced parameters - easier to read at least.
print('sample_str_{}'.format("apple")) should return 'sample_str_apple'.
If you're using Python 3.6 you also have access to Python's formatted string literals.
>>> greeting = 'hello'
>>> name = 'Jane'
>>> f'{greeting} {name}'
'hello Jane'
Note that the literal expects the variables to be already present. Otherwise you get an error.
>>> f'the time is now {time}'
NameError: name 'time' is not defined

Dynamically allocate variables

I have a dictionary that contains variable names and their corresponding values I would like to allocate dynamically
dict_ = {'var1':'cvx.Variable(3)', 'var2':'3'}
In my code I then do
for k,v in dict_.iteritems():
exec("global %s;%s=%s" % (k,k,v))
print k, type(k)
For the integer variable this works and I get 3 type 'int', however for var1 ( import cvxpy as cvx) I get k type 'str'. Where I would want to get
class 'cvxpy.expressions.variables.variable.Variable'
Any advise what I am doing wrong ?
EDIT: I am receiving the dictionary entries as a string input like
"var1 = cvx.Variable(3),var2 = 3"
which I then transform into the dictionary
Why you should not use non-string dict_ values:
As stated in its documentation, the % operator calls the str() built-in function when used with the %s format.
When str() is called on a cvxpy.Variable instance, it returns a string with the format varX where X is an integer (the index of the created variable in memory, I suppose):
>>> import cvxpy
>>> x = cvxpy.Variable(3)
>>> str(x)
'var0'
Unfortunately, this format happens to be the naming convension used by the string you receive for its variables.
Defining dict_ = {'var1':cvx.Variable(3), 'var2':3} will not only not solve your issue but may silently succeed as the value at dict_['var1'], passed to str(), may return a varX value on the right side of the assignment that you build with % that refers to an existing variable (declared before the loop or through the global passed to exec()).
Instead, you code should work and your issue certainly lies outside of what you are sharing with us.
As an example, I run the following code on my machine (Python 2.7.12):
>>> import cvxpy
>>> cvxpy.__version__
'1.0.6'
>>> d = {'var1': 'cvxpy.Variable(3)', 'var2': '3'}
>>> for k, v in d.iteritems():
... s = 'global %s; %s = %s' % (k, k, v)
... print s
... exec(s)
...
global var1; var1 = cvxpy.Variable(3)
global var2; var2 = 3
>>> print var1, type(var1)
var0 <class 'cvxpy.expressions.variable.Variable'>
>>> print var2, type(var2)
3 <type 'int'>
Notice that print var1 prints var0 as explained above!
It looks like most of the comments and the solution here seem to contain some confusion between the running code, the string parsing and the executed code: anything that you are going to exec should be a str! If it is not then it will become a str by directly or indirectly calling the str() built-in (as done by your call to %) because exec takes a string.
If the string is already properly formatted as you suggest, have you considered doing something like the following?
str_in = "var1 = cvx.Variable(3),var2 = 3"
exec(str_in.replace(',', ';'))
NB: Here, I make the assumption that you are at the proper scope to not require the global but a bit more string parsing (split, strip, ...) would make it trivial to first declare the variables as globals.
When you are putting those variables in the dictionary, you are explicitly setting them as strings. Do this instead:
dict_ = {'var1':cvx.Variable(3), 'var2':3}
Assuming you want var2 to be int rather than str. Otherwise, when you wrap the value for var1 in quotes, it will default to a stringType
EDIT:
PicTo is correct regarding your implementation, because you are using %s formatting, you are automatically converting your variable to a stringType. What may be more along the lines of what you're looking for is this:
dict_ = {'var1':cvx.Variable(3), 'var2':3}
globals().update(dict_)
That will put the variables in global scope and keep your types consistent, assuming you want the variables in global scope. If you don't, locals() supports the same paradigm
Example:
>>> mydict = {'var1':3, 'var2': "happystring"}
>>> globals().update(dict_)
>>> var1
3
>>> var2
'happystring'

Force function argument to be a string

So, my code is like this:
def func(s,x):
return eval(s.replace('x',x)
#Example:
>> func('x**2 + 3*x',1)
4
The first argument of the function func must be a string because the function eval accepts only string or code objects. However, I'd like to use this function in a kind of calculator, where the user types for example 2 + sin(2*pi-0.15) + func(1.8*x-32,273) and gets the answer of the expression, and it's annoying always to have to write the quotes before in the expression inside func().
Is there a way to make python understands the s argument is always a string, even when it's not between quotes?
No, it is not possible. You can't intercept the Python interpreter before it parses and evaluates 1.8*x-32.
Using eval as a glorified calculator is a highly questionable idea. The user could pass in all kinds of malicious Python code. If you're going to do it, you should provide as minimal an environment as possible for the code to run in. Pass in your own globals dict containing only the variables the user is allowed to reference.
return eval(s, {'x': x})
Besides being safer, this is also a better way to substitute x into the expression.
You could have it handle both cases:
def func(s, x=0):
if isinstance(s, basestring):
# x is in the scope, so you don't need to replace the string
return eval(s)
else:
return s
And the output:
>>> from math import *
>>> func('2 + sin(2*pi-0.15) + func(1.8*x-32,273)')
-30.1494381324736
>>> func('x**2 + 3*x', 1)
4
Caution: eval can do more than just add numbers. I can type __import__('os').system('rm /your/homework.doc') and your calculator will delete your homework.
In a word: no, if I understand you.
In a few more, you can sort of get around the problem by making x be a special object. This is how the Python math library SymPy works. For example:
>>> from sympy import Symbol
>>> x = Symbol('x')
>>> x**2+3*x
x**2 + 3*x
>>> (x**2+3*x).subs(x,1)
4
There's even a handy function to turn strings into sympy objects:
>>> from sympy import sympify, pi
>>> sympify("x**2 - sin(x)")
x**2 - sin(x)
>>> _.subs(x, pi)
pi**2
All the warnings about untrusted user input hold. [I'm too lazy to check whether or not eval or exec is used on the sympify code path, and as they say, every weapon is loaded, even the unloaded ones.]
You can write an interpreter:
import code
def readfunc(prompt):
raw = input(prompt)
if raw.count(',')!=1:
print('Bad expression: {}'.format(raw))
return ''
s, x = raw.split(',')
return '''x={}; {}'''.format(x, s)
code.interact('Calc 0.1', readfunc)

python string to code for function arg?

I have a function names "myfunction". I have a string "a", I need to pass it to "myfunction" so it will give the same result as if my string was a python object name, myfunction(a)
So I have
def myfunction(var):
print var
a = 1
mystring = "a"
I need to pass "mystring" to "myfuntion" so it will behave as variable "a" was passed to it.
I thought of something like this, but it won't work:
myfunction(exec(mystring))
PS. Yes, I know of the consequences of exec(), please there is no need to explain that.
It would be eval(), not exec:
myfunction(eval(mystring))
Alternatively:
myfunction(locals()[mystring])
Most probably you have a fundamental design problem if you think you need something like this.
No needs in exec or eval:
>>> def myfunc(var):
... print globals()[var] * 2
...
>>> a = 12
>>> myfunc('a')
24

How to retrieve a variable's name in python at runtime?

Is there a way to know, during run-time, a variable's name (from the code)?
Or do variable's names forgotten during compilation (byte-code or not)?
e.g.:
>>> vari = 15
>>> print vari.~~name~~()
'vari'
Note: I'm talking about plain data-type variables (int, str, list etc.)
Variable names don't get forgotten, you can access variables (and look which variables you have) by introspection, e.g.
>>> i = 1
>>> locals()["i"]
1
However, because there are no pointers in Python, there's no way to reference a variable without actually writing its name. So if you wanted to print a variable name and its value, you could go via locals() or a similar function. ([i] becomes [1] and there's no way to retrieve the information that the 1 actually came from i.)
Variable names persist in the compiled code (that's how e.g. the dir built-in can work), but the mapping that's there goes from name to value, not vice versa. So if there are several variables all worth, for example, 23, there's no way to tell them from each other base only on the value 23 .
Here is a function I use to print the value of variables, it works for local as well as globals:
import sys
def print_var(var_name):
calling_frame = sys._getframe().f_back
var_val = calling_frame.f_locals.get(var_name, calling_frame.f_globals.get(var_name, None))
print (var_name+':', str(var_val))
So the following code:
global_var = 123
def some_func():
local_var = 456
print_var("global_var")
print_var("local_var")
print_var("some_func")
some_func()
produces:
global_var: 123
local_var: 456
some_func: <function some_func at 0x10065b488>
here a basic (maybe weird) function that shows the name of its argument...
the idea is to analyze code and search for the calls to the function (added in the init method it could help to find the instance name, although with a more complex code analysis)
def display(var):
import inspect, re
callingframe = inspect.currentframe().f_back
cntext = "".join(inspect.getframeinfo(callingframe, 5)[3]) #gets 5 lines
m = re.search("display\s+\(\s+(\w+)\s+\)", cntext, re.MULTILINE)
print m.group(1), type(var), var
please note:
getting multiple lines from the calling code helps in case the call was split as in the below example:
display(
my_var
)
but will produce unexpected result on this:
display(first_var)
display(second_var)
If you don't have control on the format of your project you can still improve the code to detect and manage different situations...
Overall I guess a static code analysis could produce a more reliable result, but I'm too lazy to check it now
This will work for simple data types (str, int, float, list etc.)
def my_print(var_str) :
print var_str+':', globals()[var_str]
You can do it, it's just not pretty.
import inspect, sys
def addVarToDict(d, variable):
lineNumber = inspect.currentframe().f_back.f_lineno
with open(sys.argv[0]) as f:
lines = f.read().split("\n")
line = lines[lineNumber-1]
varName = line.split("addVarToDict")[1].split("(")[1].split(",")[1].split(")")[0].strip()
d[varName] = variable
d = {}
a=1
print d # {}
addVarToDict(d,a)
print d # {'a': 1}
I tried the following link from the post above with no success:
Googling returned this one.
http://pythonic.pocoo.org/2009/5/30/finding-objects-names
Just yesterday I saw a blog post with working code that does just this. Here's the link:
http://pyside.blogspot.com/2009/05/finding-objects-names.html
Nice easy solution using f-string formatting, which is native to Python 3.6 and later:
vari = 15
vari_name = f"{vari=}".split("=")[0]
print(vari_name)
Produces:
vari

Categories