How can I generate a variable name from a string (say a concatenation of a letter and a number) ?
In Matlab, this task can be easily done using genvarname
Here's a really bad way (undefined behavior), but I think it shows the path to a more reasonable technique.
Your current namespace is really a dictionary under the covers:
>>> local_namespace = locals()
>>> name = "myVarName"
>>> local_namespace[name] = 'VarData'
>>> myVarName
'VarData'
But that's not very DRY - you have to write the name of the variable twice! It would be nice to use a variable that stored the name of our dynamically created variable so we didn't have to type it twice:
>>> name
'myVarName'
obviously doesn't work for this. But we can use our dictionary again:
>>> local_namespace[name]
'VarData'
So now we can store and recall the value associated with our variable. But wait - there's no need to use the special locals() dictionary for this - an ordinary dictionary will do!
>>> d = {}
>>> d[name] = 'VarData'
>>> d[name]
'VarData'
And now we have all these added benefits, like being able to keep track of the names of several of these variables in a list:
>>> l = []
>>> l.append('myVarName')
>>> l.append('anotherVarName')
Dictionaries even do this for us:
>>> d['anotherVarName'] = 123
>>> d.keys()
['myVarName', 'anotherVarName']
Unless you're doing terrifically wacky things, it's hard to imagine how constructing variable names could be more useful than using a dictionary.
You can use exec("").
But you really(!!!) don't want to.
>>> name="myVarName"
>>> exec(name+"='VarData'")
>>> myVarName
'VarData'
Related
I am aware there is a way of always setting multiple variables of a list or dictionary by initializing variables by a comma and setting variable with the list / dict that is wanted.
Example is that I have a description that I split so many times due to redundancy and I want to make the variables easily accessible.
spl_desc = desc.replace(" ", "").split("<hr>")
part_one = spl_desc[0].split()
part_two = spl_desc[1].split()
And then both parts are split again as the first variable of the second split for both first parts are the exact same and the second part is slightly different but most of the time the same.
redundant_var_one_part_one = part_one[0]
almost_redundant_des_one = part_one[1]
redundant_var_one_part_two = part_two[0]
almost_redundant_des_two = part_two[1]
Bonus question to this, would it be possible to set those variables again directly while splitting those variables?
EDIT QUESTION
In PHP the above would look like this
list(redundant_var_one_part_one, almost_redundant_des_one) = part_one;
list(redundant_var_one_part_two, almost_redundant_des_two) = part_two;
Each variable is set "inline" and avoids setting every item in the array.
Bonus question example. In PHP would be something like
list(part_one, part_two) = explode(str_replace(" ", "", desc), "<hr>");
It looks like what you're asking for is just implicit in Python assignment:
a, b = [item_one, item_two]
e.g.:
>>> a, b = ["foo", "bar"]
>>> a
'foo'
>>> b
'bar'
or:
>>> some_vars = [23, 34]
>>> a, b = some_vars
>>> a
23
>>> b
34
I'm working on rewriting a lengthy Rexx script into a Python program and I am trying to figure out the best way to emulate the functionality of a Rexx compound variable. Would a dictionary be the best bet? Obviously, a dictionary will behave differently and won't be exactly the same as a compound variable.
Python dictionaries and Rexx stems are both associative arrays. They differ a bit in how they behave. Rexx's rules are very simple:
An array reference is split into the "stem" and the "tail", separated by a single dot.
The stem is a variable name, case-independently. This is the dictionary.
The tail is processed to identify an element of the array. It is split into one or more dot-separated substrings. Each substring is treated as a variable: if there is a variable with that case-independent name, its value is used instead of its name. Otherwise the name is uppercased and used. The string is put back together, dots and all. This is the key.
The array can have a default value, set by stem. = value, which applies to all unset elements.
So, the result of a an array reference stem.tailpart1.tailpart2.tailpart3 in Python is:
def evaluate_tail(tail, outer_locals):
result = []
for element in tail.split('.'):
if element in outer_locals:
result.append(str(outer_locals[element]))
else:
result.append(str(element).upper())
return '.'.join(result)
array_default_value = 4
stem = {'A.B.C': 1, 'A.9.C': 2, 'A..q': 3}
b = 9
d = 'q'
tail1 = 'a.b.c'
tail2 = 'a..b'
tail3 = 'a..d'
stem.get(evaluate_tail(tail1,locals()), array_default_value) # 'stem.a.b.c' >>> stem['A.9.C'] >>> 2
stem.get(evaluate_tail(tail2,locals()), array_default_value) # 'stem.a..b' >>> stem['A..9'] (not found) >>> (default value) >>> 4
stem.get(evaluate_tail(tail3,locals()), array_default_value) # 'stem.a..d' >>> stem['A..q'] >>> 3
Rexx-Stem variable and python-dictionaries are similar but there are differences.
Considder creating a RexxStem class based on a dictionary
Simple Stem expressions
a.b
can be translated to python as
a[b]
Compound Stem expressions
From my experience
a.b.c.d
would be translated to python as
a[b + '.' + c + '.' + d]
Try running the following rexx with your current interpretter and see what you
get:
a.2.3 = 'qwerty'
zz = 2'.'3
say a.zz
in some rexx interpreters you would get 'qwerty'. Not sure if that is all
Initializing a Stem Variables
in rexx you can initialize a stem variable lic
a. = 'abc'
Some common uses are
no = 0
yes = 1
found. = no
if ... then do
found.v = yes
end
....
if found.y = yes then do
..
end
or
counts. = 0
do while ...
if ... then do
counts.v = counts.v + 1;
end
end
Initial Value of a stem variable
Like all Rexx variables, the default/initial value of a variable so the default value of a.2.3 is A.2.3. If you are coming from another language this may seem strange but it can be quite handy in debugging - if a variable name pops up unexpectedly --> you have not initiated. It also means numeric expressions crash if you do not initialize a variable.
This not something you need to implement, just be aware of.
I am not a Python person but I know what a Dictionary is.
Depending on how complex the Rexx compound variable is, yes.
a.b
...is easily translatable to a dictionary.
a.b.c.d.e.f.g.h
...is less easily translatable to a dictionary. Perhaps a dictionary within a dictionary within a dictionary within a dictionary within a dictionary within a dictionary within a dictionary.
This question already has answers here:
How to copy a dictionary and only edit the copy
(23 answers)
Closed 8 years ago.
I'm expecting my frustration to be overridden with some enlightenment - here's a minimal version of the script to demonstrate the problem:
First I create a dictionary:
dic = {
'foo':{},
'bar':{}
}
Then we instantiate a template dictionary that can be iteratively appended
to keys of dic:
appendic= {
'is':'', # '' is a terminal value to be replaced later
}
So here we append appendic to each of the keys in dic:
dic['foo'] = appendic
dic['bar'] = appendic
Now we replace the terminal values, '', with something meaningful:
dic['foo']['is'] = 'foo'
dic['bar']['is'] = 'bar'
At this point, my intuition tells me that if we call:
print(dic['foo']['is']) we get 'foo'
But instead Python returns 'bar' ... to my un-trained mind that is counter-intuitive.
Questions:
How can I tell Python to keep the keys of dic independent?
Why is this the default behaviour? What use cases does this have?
When you assign a appendic to two different keys, Python doesn't make a copy. It assigns a reference instead.
As a result, both dic['please_make_me_Foo'] and dic['dont_make_him_Bar'] refer to the same object. These are not separate dictionaries, they are both the same object, the one appendic also references to.
If you expected these to be separate dictionaries, create a copy of appendic instead. The dict.copy() method creates a shallow copy of a dictionary:
dic['please_make_me_Foo']= appendic.copy()
dic['dont_make_him_Bar'] = appendic.copy()
Shallow means that a new dictionary is created and all references to keys and values contained are copied over.
If appendic itself contains values that are also dictionaries, these would not be copied. The new copy and appendic would both refer to the same values. In most cases, that's not a problem because most primitive values (strings, integers, etc.) are immutable, and you never notice references are shared as you replace such values with new ones.
You make a dict:
appendic= {
'Python_made_me':''
}
Add it to your other dict twice
dic['please_make_me_Foo']= appendic
dic['dont_make_him_Bar'] = appendic
And set the single dict's Python_made_me value twice
dic['please_make_me_Foo']['Python_made_me'] = 'Foo'
dic['dont_make_him_Bar']['Python_made_me'] = 'Bar'
But because they're the same dict, the second line overwrites the first
If you need to copy it, you need to use the copy method:
dic['please_make_me_Foo']= appendic.copy()
dic['dont_make_him_Bar'] = appendic.copy()
ok, I'm just going to write this as a complement to the other answers. When you manipulate a dictionary, you manipulate the reference to an instance, which is the root cause of your mistake. Using hex(id(foo)) you get the memory address of foo, so let's show the address of d instance in the following example to make that tangible:
>>> hex(id(d))
'0x10bd95e60'
>>> hex(id(e[1]))
'0x10bd95e60'
>>> hex(id(f[1]))
'0x10bd95e60'
so if you add or remove values from e[1], you're actually changing the same instance as the one pointed by d, and as a dictionary is mutable, i.e. you can change values within.
Now you're wondering why that does not happen when you're handling integers? Because, in fact it does, it's just that integers are not mutable:
>>> i = 1
>>> hex(id(i))
'0x10ba51e90'
>>> j = i
>>> hex(id(j))
'0x10ba51e90'
>>> i = 2
>>> hex(id(i))
'0x10ba51eb0'
i.e. i is pointing to another place in the memory.
It's possible to create a mutable integer though, by using a class:
>>> class Integer:
... def __init__(self, i):
... self.i = i
...
>>> i = Integer(2)
>>> hex(id(i))
'0x10bd9b410'
>>> j = i
>>> hex(id(j))
'0x10bd9b410'
>>> j.i = 2
>>> i.i
2
>>> hex(id(i))
'0x10bd9b410'
In order to create a new instance of the same dictionary, you need to use the copy() member of a dict:
>>> hex(id(d))
'0x10bd95e60'
>>> w = d.copy()
>>> x = d.copy()
>>> y = d.copy()
>>> hex(id(w))
'0x10bd96128'
>>> hex(id(x))
'0x10bd95f80'
>>> hex(id(y))
'0x10bd96098'
dic['please_make_me_Foo']= appendic
dic['dont_make_him_Bar'] = appendic
appendic is an object - you are assigning a reference to the same object to both keys in dic. So when you change one, you change both.
Try this instead:
dic['please_make_me_Foo']= appendic.copy()
dic['dont_make_him_Bar'] = appendic.copy()
I got two strings retrieved from a cookie
name = 'rack.session'
val = 'CookieVal'
Using them I would like to build a dictionary
cookies = dict(rack.session=val)
but SyntaxError: keyword can't be an expression
So I tried to escape the (.) dot
re.escape(name)
... but it raises the same error
How is this possible? According to Python type() name is a string:
type(name)
<class 'str'>
Why is Python mixing up strings and expressions?
The problem with rack.session is that python thinks that you're trying to use the value of expression rack.session and pass it to dict(), which is incorrect because dict() expects you to pass variables names when you're using keyword arguments, these variables name are then converted to strings when the dict is created.
Simple example:
>>> dict('val' = 'a')
File "<ipython-input-21-1cdf9688c191>", line 1
SyntaxError: keyword can't be an expression
So, you can't use an object on the left side of =, you can only use a valid identifier.
Byte code makes it even more clear what happens with rack.session:
>>> import dis
>>> dis.dis(lambda : dict(rack.session , val))
1 0 LOAD_GLOBAL 0 (dict)
3 LOAD_GLOBAL 1 (rack) # load the object `rack`
6 LOAD_ATTR 2 (session)# use the value of it's attribute
# `session`
9 LOAD_GLOBAL 3 (val)
12 CALL_FUNCTION 2
15 RETURN_VALUE
So, with rack.session = val, python will think that you're trying to use the value returned from rack.session and pass it to dict, which is incorrect. Secondly rack.session isn't a valid identifier as dots(.) are not allowed in python identifiers.
This is applicable to any function in python not even dict, a keyword argument must be a valid identifier.
From the docs:
keyword_item ::= identifier "=" expression
Valid examples:
>>> dict(foo = 1, bar = '2')
{'foo': 1, 'bar': '2'}
For your example you can simply do:
>>> val = 'CookieVal'
>>> name = 'rack.session'
>>> dict(((name,val),))
{'rack.session': 'CookieVal'}
#or
>>> {name:val}
{'rack.session': 'CookieVal'}
>>> name = 'rack.session'
>>> val = 'CookieVal'
>>> cookies = {name: val}
>>> cookies
{'rack.session': 'CookieVal'}
name = 'rack.session'
val = 'CookieVal'
cookies = dict([(name,val)])
morecookies = {name:val}
As to "Why is Python mixing up strings and expressions?", it's not. I'm not sure why you think python is doing this. You are mixing up strings and variables, which are quite different.
You should build a dictionary this way
name = 'rack.session'
val = 'CookieVal'
d = {name: val}
print d
gives you
>>>
{'rack.session': 'CookieVal'}
>>>
More on dictionaries http://docs.python.org/2/tutorial/datastructures.html#dictionaries
The reason is that you give the dict this expression: rack.session=val, rather than a keyword.
Instead, you can get around this issue using dict({name: val}), where the argument is {name:val}. Of course, you could just use {name: val}.
The python docs shows several ways to create dicts.
The answer from Ashwini Chaudhary was quite good, but I can add more to clarify question.
The main reason why you've got this error is because your expression contain a point - '.' symbol. And raising error directly say that: "keyword can't be an expression".
This - '.' symbol makes Python think, that current keyword name is not a valid name, but an expression, that you try to evaluate. Generally speaking you may pass as a key in dict() only valid name, from the point that such names could be a names for a variables dispite the fact that no variable evaluation actually can be happen here.
So your keys must contain only alphabeticals, digits, or underscore, and do not start with a digit (they must be valid Python identifiers as was said before).
For example these are not valid:
d = dict(1='Bob')
d = dict(b.a='Bob')
d = dict('b'='Bob')
d = dict(b$='Bob')
First, second and third are not valid, because they are expressions and because they are not valid identifiers, but fourth only because it is not a valid identifier.
To circumvent current limitations you may use one of the ways that was mentioned above, cause they accepting variable evaluation and if the key is the string, it can contain any characters:
d = dict([(1, 'Bob')])
d = dict(zip([1],['Bob']))
d = {1:'bob'}
or this one:
d = dict.fromkeys([1])
d[1] = 'Bob'
And for example of key value evaluation difference:
x = 1
d = dict(x='Bob')
d
{'x': 'Bob'}
x = 1
d = dict([(x, 'Bob')])
d
{1: 'Bob'}
Try this:
name = 'rack.session'
val = 'CookieVal'
cookies = dict(zip([name],[val]))
Edit: my case is too much for your case
cookies = {name:val}
is enough
May it's very simple question, but I'm stuck here.
I have variable val as val="mandy", now i want to create a list whose name is the content of val. i.e. "mandy". so how to define mandy=[] in python.
It's like "$$" equivalent of PHP.
You can do something like this in Python, but it's very un-Pythonic to do so (whereas it's a common PHP idiom as I gather). Don't use the language in a way it's not intended to be used.
What you're trying to do is much better done by using a dictionary, a maximally optimized datatype in Python:
>>> val = "mandy"
>>> mydict = {}
>>> mydict[val] = []
>>> mydict[val].append("Hello")
>>> mydict[val].append("Mandy")
>>> mydict
{'mandy': ['Hello', 'Mandy']}
There is no pythonic way to create variables with variable names. Doing so is a bad practice. Instead, use a dictionary:
val = "mandy"
mynames = {}
mynames[val] = []
You can now access mynames["mandy"] to get or modify the list.
Note that you can achieve a php-like behavior in some Python implementations by modifying locals, like
>>> locals()['mandy'] = []
>>> mandy
[]
Doing so is strongly discouraged and will not work with some Python implementations though.
You can't (without hacks) and shouldn't.
Use a dictionary values = {"mandy": []} instead.
Why would you want a local variable whose name you don't know?! If you know its name at coding-time, use it in a garden-variety assignment. If not, it shouldn't be a local variable.
Use a dict. You can create names with getattr/setattr or playing with globals(), but you more than likely don't need it.
val = 'foo'
d = { val: [] }
Try this:
>>> val = 'mandy'
>>> vars()[val] = []
>>> mandy
[]
See more details about vars() builtin