1

EDIT 2 : since so many people are crying against the bad design this usecase can reveal. Readers of these question and answers should think twice before using it

I've trying to set a variable (not property) by it's name in Python :

foo = 'bar'
thefunctionimlookingfor('foo', 'baz')
print foot #should print baz

PS : the function to access a variable by its name (without eval) would be a plus !

EDIT : I do know dictionary exists, this kind of usage is discouraged, I've choose to use it for a very specific purpose (config file modification according to environment), that will let my code easier to read.

AsTeR
  • 7,247
  • 14
  • 60
  • 99
  • 2
    You might want to look at http://stackoverflow.com/questions/8028708/dynamically-set-local-variable-in-python – George Jul 27 '12 at 12:35

6 Answers6

5

When you want variably-named variables, it's time to use a dictionary:

data = {}
foo = 'bar'
data[foo] = 'baz'
print data['bar']
Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
  • This was not my question, my question was how to set local variables, no how to workaround that need – AsTeR Jul 27 '12 at 12:37
  • 1
    @AsTeR: you should accept one of the other answers then. Also, you should stop trying to do this. Dictionaries were meant to solve this problem. – Ned Batchelder Jul 27 '12 at 12:39
  • I know dictionary exist, I also know that I should accept answer on SO if any fits my question. And I also know what I do, thanks for caring (the edit of the question explains a bit that point) ! – AsTeR Jul 27 '12 at 12:43
  • 2
    @AsTeR: Please read Ned's nice blog post [Keep data out of your variable names](http://nedbatchelder.com/blog/201112/keep_data_out_of_your_variable_names.html) (in particular the discussion). And please consider the possibility that you are wrong on this one. – Sven Marnach Jul 27 '12 at 12:46
  • I do consider that I might be wrong. I'm not having the usecase described in your article. Tell me your opinion : I've a config.py module, I call 'config.tmpPath' for example, this config has to partially change according to what the user want. I've a dictionnary of dictionnary (one per potential configuration) containing the variable that should be changed. I don't want to have to call config.getMyVar(name, concreteConfig) (I'd lose autocompletion and have a lot more text), I prefer to call config.use(concreteConfig) to update config module variables and then call config.name. – AsTeR Jul 27 '12 at 12:58
  • 2
    @AsTeR: In that case, I suggest to make `config` an instance of a custom class, and to use `setattr()` and `getattr()`. Dynamically named *attributes* have their use cases, but dynamically named *variables* don't. (This seems to be an instance of the XY problem: You did not ask about your actual problem, but about the attempted solution.) – Sven Marnach Jul 27 '12 at 13:03
  • @SvenMarnach +1 even if I do not really understand why is it better in a class – AsTeR Jul 27 '12 at 13:06
  • @AsTeR: Modules are not meant to be used that way, so it would surprise readers of the code and users of the library. Moreover, classes have much better support for dynamic attributes, including the `__getattr__()`, `__getattribute__()` and `__setattr__()` special methods as well as descriptors. – Sven Marnach Jul 27 '12 at 13:19
  • @AsTeR: Regardless which solution you choose, you need to be very careful since you are mixing namespaces: the functions/methods to modify the configuration and the configuration variables itself. In your example, consider what happens if someone sets the variable `use` to some value – subsequent calls to `config.use()` would fail. – Sven Marnach Jul 27 '12 at 13:34
  • I do, I do, this could also occurs with setattr I think (I do not test) – AsTeR Jul 27 '12 at 13:47
3

Dynamically setting variables in the local scope is not possible in Python 2.x without using exec, and not possible at all in Python 3.x. You can change the global scope by modifying the dictionary returned by globals(), but you actually shouldn't. Simply use your own dictionary instead.

Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
3

You can do something like:

def thefunctionimlookingfor(a, b):
    globals()[a] = b

Usage:

>>> foo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'q' is not defined
>>> thefunctionimlookingfor('foo', 'bar')
>>> foo
'bar'

But this is a terrible idea, as others have mentioned. Namespaces are a useful concept. Consider a redesign.

Adeel Zafar Soomro
  • 1,492
  • 9
  • 15
1

At the module level you can use setattr on the current module, which you can get from sys.modules:

setattr(sys.modules[__name__], 'name', 'value')
Simon Sapin
  • 9,790
  • 3
  • 35
  • 44
0

The locals() function returns a dictionary filled with the local variables.

locals()['foo'] = 'baz'
Niklas R
  • 16,299
  • 28
  • 108
  • 203
  • That do not work inside of a function indeed, but outside it works – AsTeR Jul 27 '12 at 12:44
  • 3
    @AsTeR: Then you should be using `globals()` instead of `locals()`. The documentation of `locals()` states that the returned dictionary must not be modified. – Sven Marnach Jul 27 '12 at 12:47
0

Are you looking for functions like these? They allow modifying the local namespace you happen to be in.

import sys

def get_var(name):
    return sys._getframe(1).f_locals[name]

def set_var(name, value):
    sys._getframe(1).f_locals[name] = value

def del_var(name):
    del sys._getframe(1).f_locals[name]
Noctis Skytower
  • 21,433
  • 16
  • 79
  • 117