3

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.

Andrew Youdin
  • 83
  • 1
  • 1
  • 6

6 Answers6

5

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
Community
  • 1
  • 1
Jesse Vogt
  • 16,229
  • 16
  • 59
  • 72
  • 2
    There is almost never a reason to use eval or exec. You can use getattr or setattr instead, in this case. – Keith Feb 08 '13 at 01:40
  • For my own learning, how would you use setattr in this context? – Jesse Vogt Feb 08 '13 at 02:42
  • Your edited answer is one way to directly set a global variable. But I usually reserve globals for constant (read-only) values that are truly global. If you need to keep state then use a class and instance variables. – Keith Feb 08 '13 at 05:26
  • @JesseVogt Thanks for the direct answer to the original question. I appreciate the other posts saying that `exec` is a bad thing to rely on, but it's good to know it's there in a bind. – Andrew Youdin Feb 08 '13 at 23:29
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.

Community
  • 1
  • 1
Moshe
  • 9,283
  • 4
  • 29
  • 38
1

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.

Demian Brecht
  • 21,135
  • 5
  • 42
  • 46
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.

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()
SingleNegationElimination
  • 151,563
  • 33
  • 264
  • 304
  • I'm sure you're right that this is the best big picture answer. I know I need to learn how to use classes in my code. So considering that I'm doing all this in a module that has a lot of different interacting functions, then I guess I should just wrap all these related functions in a class to have more control of the parameters they all share. I guess that would avoid or at least help with the problem of all these functions having to pass parameters back and forth. – Andrew Youdin Feb 08 '13 at 05:38
0

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'

sebtac
  • 538
  • 5
  • 8
-3

You can use the following solution:

s = 'x'
locals()[s] = 1
Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140