Set the name of a python object/variable with a string - python

Most people will probably say this is a bad idea. I want to use the content of a string as the name of a variable. I want to accomplish the dreaded:
s = 'x'
x = 1
where the variable name x comes (somehow?) from the string s.
To answer the "why?", say I have a global default value for x that I want the option of overriding in a function. But:
x = 0
def f(**kw):
print x
f(x=1)
prints 0 not 1. If I could use the strings in kw.keys() to reassign x (or any other globally set variables) then I'd be happy.
I realize that this works for reassigning x in f:
x = 0
def f(x=x):
print x
f(x=1)
But I want to do this for cases where there are MANY variables in my namespace that I might at some point want to override without rewriting every function definition in my module.

Check out exec
>>> print x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> s = 'x'
>>> exec(s + " = 1")
>>> print x
1
See also: How can I assign the value of a variable using eval in python?
After a little experimentation, this also seems to work:
>>> print x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> s = 'x'
>>> globals()[s] = 1
>>> print x
1

You should reconsider using the global keyword (http://docs.python.org/2.7/reference/simple_stmts.html#the-global-statement)
I recommend taking a look at Use of "global" keyword in Python as well.
Also, as promanow suggested, using a global mutable object might be a better approach.
However, keep in mind that having large amounts of code that might modify or depend on a mutating global is very scary idea, from a maintenance perspective. Tread carefully.

Assignment via function arguments is not obvious and therefore is not considered Pythonic (Python is not C). See import this.
The cheap way that I've done flat configuration is through a global partial dict:
In [1]: from functools import partial
In [2]: config = partial(dict)
In [3]: def f(x=None):
...: print x or config.x
...:
In [4]: config.x = 'foo'
In [5]: f()
foo
Something to this effect is obvious, readable and therefore much more maintainable.

But I want to do this for cases where there are MANY variables in my namespace that I might at some point want to override without rewriting every function definition in my module.
It sounds like you want a class:
class Foo(object):
x = 0
def f(self):
print self.x
my_foo = Foo()
my_foo.x = 1
my_foo.f()

I use the following for creating dynamically custom modeling databses for targets of interest from one global database:
DBs = ["Target_1_DB","Target_2_DB","Target_3_DB"]
for db in DBs:
print(db)
exec_str = "Modeling_DB_Base = " + db
exec(exec_str)
#s = "Modeling_DB_Base"
#globals()[s] = db
print(Modeling_DB_Base.shape)
using the commented-out globals() results in error message: AttributeError: 'str' object has no attribute 'shape'

You can use the following solution:
s = 'x'
locals()[s] = 1

Related

Is there a way to replace an string with a variable of the same name? [duplicate]

This question already has answers here:
How do I create variable variables?
(17 answers)
Closed 1 year ago.
This is probably a really novice question, so forgive me.
If I know the name of an instance/variable - let's say I have a string called "variable_name" and a variable with the same name, how would I go about writing a piece of code that takes that string and converts it into something I can actually use and use class methods on, etc? Is that a thing that can happen at all?
Edit: Added some code to better articulate my question. I've got a code setup kind of like this (simplified for space):
class Class_Name:
count = 0
def __init__(self, foo, bar):
self.__class__.count += 1
self.foo = foo
self.bar = bar
def find_variable_name(class_name, number):
variable_name = "variable" + str(number)
return variable_name
variable1 = Class_Name("foo", "bar")
variable2 = Class_Name("foo2", "bar2")
variable3 = Class_Name("foo3", "bar3")
for instances in range(Class_Name.count):
print (find_variable_name(Class_Name, instances+1).foo)
This would give me the error "AttributeError: 'str' object has no attribute 'foo'" - how would I turn the object from a string to something I can work with?
You can simply use exec() function:
k = "my_str" # a string
exec(k + " = k") # my_str = "my_str"
Then, the output is:
>>> print(my_str)
'my_str'
The exec() function executes the string given it.
So, when we do exec(k + " = k"), it means, exec("my_str = k"), which assigns the value of the variable k to my_str.
This makes my_str = "my_str".
NOTE:
Be a little wary of the exec() function, especially if the value of the variable is user-inputted. Then, it could be dangerous to use.
locals() returns a dictionary of the variable bindings of the current scope.
The keys of the dictionary are strs so you can do lookup using the variable name. E.g.
>>> somevariable = 1
>>> locals()["somevariable"]
1
Of course it may be that the variable you want is not in the current scope, then it will not be in locals(). However, if it is in the global scope, you can use globals() in the same way. E.g.
>>> somevariable = 1
>>> globals()["somevariable"]
1
So in your example above, you might use a function like:
def find_variable_name(number):
return globals()["variable" + str(number)]
Which you can use as:
>>> variable1 = Class_Name("foo", "bar")
>>> find_variable_name(1).foo
'foo'
NOTE THAT this type of thing is not good programming practice. Doing this makes code harder to read and understand and maintain. Depending on your application, it might be better just to keep a Dict of your objects, indexing with the counts. E.g.
>>> d = {i: Class_Name("foo", "bar") for i in range(10)}
>>> d[1].foo
'foo'

Is there a way to define a variable that is a parameter inside a function in Python?

Is it possible to define a variable that is a parameter inside a function?
I've tried doing this:
def myfunc(variable):
variable = 5
myfunc(x)
print(x)
I was expecting to see the number "5" printed on my screen, because I'm defining x (which is 5) and then printing it.
But I get this NameError:
Traceback (most recent call last):
File "C:\Users\yoelc\PycharmProjects\Test\app.py", line 4, in <module>
myfunc(x)
NameError: name 'x' is not defined
I know it is possible to do this:
def myfunc():
return 5
x = myfunc()
print(x)
But that's not what I'm trying to do.
Is there a way to define this?
Maybe not exactly what you want but pretty similar:
def myfunc(variable):
globals()[variable] = 5
myfunc('x')
print(x)
That being said this is a bad idea, unless you really need to use metaprogramming for some reason

How do I get the return value when using Python exec on the code object of a function?

For testing purposes I want to directly execute a function defined inside of another function.
I can get to the code object of the child function, through the code (func_code) of the parent function, but when I exec it, i get no return value.
Is there a way to get the return value from the exec'ed code?
Yes, you need to have the assignment within the exec statement:
>>> def foo():
... return 5
...
>>> exec("a = foo()")
>>> a
5
This probably isn't relevant for your case since its being used in controlled testing, but be careful with using exec with user defined input.
A few years later, but the following snippet helped me:
the_code = '''
a = 1
b = 2
return_me = a + b
'''
loc = {}
exec(the_code, globals(), loc)
return_workaround = loc['return_me']
print(return_workaround) # 3
exec() doesn't return anything itself, but you can pass a dict which has all the local variables stored in it after execution. By accessing it you have a something like a return.
I hope it helps someone.
While this is the ugliest beast ever seen by mankind, this is how you can do it by using a global variable inside your exec call:
def my_exec(code):
exec('global i; i = %s' % code)
global i
return i
This is misusing global variables to get your data across the border.
>>> my_exec('1 + 2')
3
Needless to say that you should never allow any user inputs for the input of this function in there, as it poses an extreme security risk.
use eval() instead of exec(), it returns result
Something like this can work:
def outer():
def inner(i):
return i + 10
for f in outer.func_code.co_consts:
if getattr(f, 'co_name', None) == 'inner':
inner = type(outer)(f, globals())
# can also use `types` module for readability:
# inner = types.FunctionType(f, globals())
print inner(42) # 52
The idea is to extract the code object from the inner function and create a new function based on it.
Additional work is required when an inner function can contain free variables. You'll have to extract them as well and pass to the function constructor in the last argument (closure).
Here's a way to return a value from exec'd code:
def exec_and_return(expression):
exec(f"""locals()['temp'] = {expression}""")
return locals()['temp']
I'd advise you to give an example of the problem you're trying to solve. Because I would only ever use this as a last resort.
This doesn't get the return value per say, but you can provide an empty dictionary when calling exec to retrieve any variables defined in the code.
# Python 3
ex_locals = {}
exec("a = 'Hello world!'", None, ex_locals)
print(ex_locals['a'])
# Output: Hello world!
From the Python 3 documentation on exec:
The default locals act as described for function locals() below: modifications to the default locals dictionary should not be attempted. Pass an explicit locals dictionary if you need to see effects of the code on locals after function exec() returns.
For more information, see How does exec work with locals?
Here's a solution with a simple code:
# -*- coding: utf-8 -*-
import math
x = [0]
exec("x[0] = 3*2")
print(x[0]) # 6
Since Python 3.7, dictionary are ordered. So you no longer need to agree on a name, you can just say "last item that got created":
>>> d = {}
>>> exec("def addone(i): return i + 1", d, d)
>>> list(d)
['__builtins__', 'addone']
>>> thefunction = d[list(d)[-1]]
>>> thefunction
<function addone at 0x7fd03123fe50>
if we need a function that is in a file in another directory, eg
we need the function1 in file my_py_file.py
located in /home/.../another_directory
we can use the following code:
def cl_import_function(a_func,py_file,in_Dir):
... import sys
... sys.path.insert(0, in_Dir)
... ax='from %s import %s'%(py_file,a_func)
... loc={}
... exec(ax, globals(), loc)
... getFx = loc[afunc]
... return getFx
test = cl_import_function('function1',r'my_py_file',r'/home/.../another_directory/')
test()
(a simple way for newbies...)
program = 'a = 5\nb=10\nprint("Sum =", a + b)'
program = exec(program)
print(program)

Print the variable assignment as output

I have probably a really simple question: Is it possible to print the value of a variable assignment without reentering the variable name?
I mean, when we enter let's say:
foo = 5
We get the following output:
5
I tried things like foo = 5; (as if I was using MATLAB - actually it hides the output) but, couldn't find any character that does this. Even in the tutorials I looked that, this was not mentioned.
The closest you can get to have this is to create a class overriding the __setattr__ method.
class A():
def __setattr__(self,name,value):
print(value)
self.__dict__['name'] = 1
a = A()
a.x = 1
1
No, this is not possible in Python. Variable assignments do not return anything:
>>> print(exec("a = 1"))
None
>>> a
1
>>>

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