0

i need help, please. The code is more big but i show you the idea with a example. How to transformation 'string union' to 'variable union'

Thanks

dictionary1    = {'a':1,'b':2}
p1              = 'dictionary'
p2              = 1
union           = p1+str(p2)
vars()[union]   = union
for key,value in union.items():
    print key,value
Aran-Fey
  • 39,665
  • 11
  • 104
  • 149

1 Answers1

0

Assuming your goal is to be able to access a variable with a dynamic name, the only solution that works at global, nested and local scope without a lot of fallback code (to handle both local and globally scoped names) is to use eval:

dictionary1 = {'a':1,'b':2}
p1 = 'dictionary'
p2 = 1
union = p1+str(p2)
for key, value in eval(union).items():
    print key, value

All eval(union) does is execute the contents of the string referenced by union as if it were a Python expression; as it happens, the name of a variable is a perfectly legal Python expression, so it's legal, if not super-safe, to use eval to perform the lookup for you.

If the variable is known to be in local or global scope already, you could do:

for key, value in locals()[union].items():

for key, value in globals()[union].items():

which is safer (in that it can't execute arbitrary code like eval can), but won't dynamically check local, nested and global scopes (any such checks would have to be performed manually, and nested scope would be ugly).

Note that in general, this is a bad idea. If you need to access variables by name, just make a dictionary mapping names (as strings) to the values you care about. Then you can use code like this safely, without the eval security/stability risks:

mydicts = {'dictionary1': {'a':1,'b':2}}
p1 = 'dictionary'
p2 = 1
union = p1+str(p2)
# If union is not a string in the dictionary, this will raise KeyError,
# but can't execute arbitrary code
for key, value in mydicts[union].items():
    print key, value
ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • But the OP is trying to _set_ variables by name (that `vars()[union] = …`). You can't do that with `eval`, because assignment isn't an expression (at least not until 3.8…). You _could_ do it with `exec`, but then you need all the same fallback code for locals that you were trying to avoid. – abarnert Aug 13 '18 at 22:01
  • `globals().setdefault(union, eval(union))` will work. Using `eval('dictionary1')` just returns the object pointed to by `dictionary1`, so in your answer it doesn't actually define anything in the global scope (nor the local, but it's presumably already there). If this code is being executed in a loop, the variable name of the dictionary would presumably be the same every pass, so OP could do `globals().setdefault(union, dictionary1)` with no `eval`. – Zach Gates Aug 13 '18 at 22:56
  • @abarnert: You could do it with `eval`+`compile`. `eval` only evaluates string expressions, but a statement, including assignment, can be compiled using `compile` in `'single'` mode, then immediately passed to `eval`. I tend to use `eval`+`compile` in general, because much of the code I write has to be source compatible with Py2 and Py3, and `eval`+`compile` is the only general dynamic code execution technique that works reliably on both. – ShadowRanger Aug 14 '18 at 00:48
  • @ZachGates: The OP seemed to be asking to dynamically load a variable, not set it (`dictionary1` already existed, they just wanted to load it dynamically as far as I can tell), so `eval` was sufficient. Granted, `vars()[union] = union` could be a misguided attempt at any number of things, but I interpreted it as a misguided attempt to dynamically load `dictionary1`; if they wanted to set `union` to *be* `dictionary1`, then `union = eval('dictionary1')` would work just fine. – ShadowRanger Aug 14 '18 at 00:50
  • @ShadowRanger `eval` plus `compile` is even worse than `exec` for namespaces—it will always do a `STORE_NAME` even when there's a local.. – abarnert Aug 14 '18 at 00:52
  • @abarnert: [Dynamically updating `locals` is illegal anyway](https://docs.python.org/3/library/functions.html#vars): "Note, the locals dictionary is only useful for reads since updates to the locals dictionary are ignored." That's a fundamental aspect of CPython's design; the array of locals is baked in at function compile time, and can't be expanded. `locals()`/`vars()` is just making a `dict` that maps the known names to values, but it's not able to create new, true locals. – ShadowRanger Aug 14 '18 at 00:56
  • @ShadowRanger Sure, but do you want code that will silently do the wrong thing and overwrite a global when called at local scope, instead of either raising an exception or harmlessly but uselessly modifying locals? – abarnert Aug 14 '18 at 00:57
  • @abarnert: Well, as I noted, my initial suggestion was solely to read the variable, not set it. That's legal and safe. You were the one suggesting that `vars()[union] = …` was an attempt to set a variable (it's a nonsensical line of code; I have no idea what they thought it was doing). I only pointed out `eval`+`compile` because you claimed `eval` couldn't do it (and `exec` could) when `eval` is perfectly capable of doing so. Whether it's *sane* to do so is a wholly different matter. :-) – ShadowRanger Aug 14 '18 at 01:00