Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically creating variables in Python [duplicate]

Tags:

python

Possible Duplicate:
How to programmatically set a global (module) variable?

I have a class called Variable defined as so:

class Variable():
    def __init__(self, name):
        self.name = name
        self._value = None
    def value(self):
        return self._value
    def __repr__(self):
        return self.name

I want to create 26 capital single letter instances of Variable like this:

A = Variable('A')
B = Variable('B')
...
Z = Variable('Z')

So far I've tried various solutions, and the best I've come up with is:

from string import uppercase
for char in uppercase:
    exec "%s = %s" % (char, Variable(str(char))) in None

However, this doesn't run and gives me this error:

Traceback (most recent call last):
  File "C:\Users\Administrator\Dev\python\truthtable\truthtable.py", line 7, in <module>
    exec "%s = %s" % (char, Variable(str(char))) in None
  File "<string>", line 1, in <module>
NameError: name 'A' is not defined

What am I doing wrong?

like image 535
deeb Avatar asked Feb 01 '11 05:02

deeb


4 Answers

from string import uppercase
_g = globals()
for char in uppercase:
    _g[char] = Variable(char)

Whether this is a good idea remains questionable :)

This only works for globals() (i.e. module level assignments), as the language definition explicitly states that modifying the dictionary returned by locals() may not actually change the value of any local variables.

You can also do something similar with the __dict__ of a class or instance.

like image 146
ncoghlan Avatar answered Oct 24 '22 09:10

ncoghlan


Don't try to stick this into a global variable. It's horrid. Do this instead.

import string

variables = {}
for x in string.ascii_uppercase:
    variables[x] = Variable(x)

The you access it from variables['Q'], for example.

If you want attribute access you can do:

class Variables(object): pass

and

variables = Variables()
for x in string.ascii_uppercase:
    setattr(variables, x) = Variable(x)

But in that case I'd rather create them dynamically in a Variables container class.

import string

class Variable(object):
    def __init__(self, value):
        self.value = value
    def __repr__(self):
        return "<Variable %s>" % self.value

class Variables(object):
    def __getattr__(self, n):
        if n in string.ascii_uppercase:
            v = Variable(n)
            setattr(self, n, v)
            return v
        raise AttributeError("Variables instance has no attribute %s" % n)

Usage:

>>> v = Variables()
>>> v.G
<Variable G>
>>> v.Y
<Variable Y>
>>> v.G is v.G
True

Simple and clean, no ugly hacks (well, except a getattr, and it's not that ugly), and you don't even have to make the Variables you don't need.

like image 38
Lennart Regebro Avatar answered Oct 24 '22 10:10

Lennart Regebro


The cleanest approach by far that I have ever seen is to directly add variables (i.e. attributes) to your program (i.e. main module), as answered in another question on StackOverflow:

import sys
from string import ascii_uppercase

this_module = sys.modules[__name__]
for char in ascii_uppercase:
    setattr(this_module, char, Variable(char))

print A  # Works!

PS: Python core developers worked hard so as to make modifying globals() possible (see the comments to ncoghlan's answer). So, modifying globals() is an alternative. I'm not sure why many people feel that it is not so clean, though (maybe because the fact that globals() can be modified is not explicitly documented?).

like image 11
Eric O Lebigot Avatar answered Oct 24 '22 11:10

Eric O Lebigot


Well, it's not pretty but you can access the globals() dictionary directly:

for c in 'ABC':
    globals()[c] = Variable(c)
like image 4
nimrodm Avatar answered Oct 24 '22 10:10

nimrodm