getting Python variable name in runtime - python

This is different from retrieving variable/object name at run time.
2G_Functions={'2G_1':2G_f1,'2G_2':2G_f2}
3G_Functions={'3G_1':3G_f1,'3G_2':3G_f2}
myFunctionMap=[2G_Functions,3G_Functions]
for i in myFunctionMap:
print i.??? "\n"
for j in i:
print str(j)
I want the output look like below.
2G_Functions:
2G_1
2G_2
3G_Functions:
3G_1
3G_2
How can I get the name of dictionary variable in my code?I dont know which I am calling in the loop to know its name beforehand.

Despite the pessimism of the other answers, in this particular case you actually can do what you're asking for if there are no other names names assigned to the objects identified by G2_Functions and G3_Functions (I took the liberty of fixing your names, which are not valid Python identifiers as given.) That being said, this is a terrible, terrible, terrible idea and you should not do it, because it will eventually break and you'll be sad. So don't do it. Ever.
The following is analogous to what you're trying to do:
alpha = {'a': 1, 'b': 2}
beta = {'c': 2, 'd': 4}
gamma = [alpha, beta]
listOfDefinedLocals = list(locals().iteritems())
for x, y in listOfDefinedLocals:
if y is gamma[0]: print "gamma[0] was originally named " + x
if y is gamma[1]: print "gamma[1] was originally named " + x
This will output:
gamma[1] was originally named beta
gamma[0] was originally named alpha
I accept no responsibility for what you do with this information. It's pretty much guaranteed to fail exactly when you need it. I'm not kidding.

You can't. The myFunctionMap list contains the objects, not the name attached to them 2 lines above. BTW, calling a list variable "map" isn't a good practice, maps are usually dictionaries.
You can't start a variable name with a digit, so 2G_Functions and 3G_Functions won't work.
You can sidestep the problem by creating a dictionary with appropriate names
e.g.
myFunctionMap = {
"2G_Functions" : { ... },
"3G_Functions" : { ... },
}
for (name, functions) in myFunctionMap.iteritems():
print name
for func in functions.keys():
print func

In short, you can't.
In longer, it is sort of possible if you poke deep into, I think, the gc module (for the general case) or use locals() and globals()… But it's likely a better idea to simply define the list like this:
myFunctionMap = [ ("someName", someName), … ]
for name, map in myFunctionMap:
print name
…

Try making your list of lists as a list of strings instead:
d2G_Functions={'2G_1':"2G_f1",'2G_2':"2G_f2"}
d3G_Functions={'3G_1':"3G_f1",'3G_2':"3G_f2"}
myFunctions=["2G_Functions","3G_Functions"]
for dict_name in myFunctions:
print dict_name
the_dict = eval("d"+dict_name)
for j in the_dict:
print str(j)
(I changed the name of your original variables since python identifiers cannot begin with a digit)

Related

Is there a name for this kind of variable stomping bug?

I solved a bug recently where (in Python code) a dictionary variable was initialized outside the loop, then modified and assigned to another dictionary within the loop. The expectation was that a deep copy of the variable was being assigned to the dictionary, but really it was the same variable being passed in over and over. The end result was that the dictionary contained a bunch of repeated dictionaries within it, instead of unique dictionaries for each iteration of the loop.
Something like this:
d = []
a = {"key": "value"}
for x in range(5):
a["key2"] = "value" + str(x)
d.append({"results": a})
Where the proper behavior is something more like this
d = []
for x in range(5):
a = {"key": "value", "key2": "value" + str(x)}
d.append({"results": a})
Going to write a changelog message for this fix, I was wondering if there was a proper term for this kind of bug? The best I could come up with was "variable stomping" but I believe there's more descriptive.
I would use a line like
Create a new dictionary at each iteration to prevent mutating template
This makes it clear what the original issue is and how it's solved - as for naming, the word is mutating!

How to create a dictionary based on variable value in Python

I am trying to create a dictionary where the name comes from a variable.
Here is the situation since maybe there is a better way:
Im using an API to get attributes of "objects". (Name, Description, X, Y, Z) etc. I want to store this information in a way that keeps the data by "object".
In order to get this info, the API iterates through all the "objects".
So what my proposal was that if the object name is one of the ones i want to "capture", I want to create a dictionary with that name like so:
ObjectName = {'Description': VarDescrption, 'X': VarX.. etc}
(Where I say "Varetc..." that would be the value of that attribute passed by the API.
Now since I know the list of names ahead of time, I CAN use a really long If tree but am looking for something easier to code to accomplish this. (and extensible without adding too much code)
Here is code I have:
def py_cell_object():
#object counter - unrelated to question
addtototal()
#is this an object I want?
if aw.aw_string (239)[:5] == "TDT3_":
#If yes, make a dictionary with the object description as the name of the dictionary.
vars()[aw.aw_string (239)]={'X': aw.aw_int (232), 'Y': aw.aw_int (233), 'Z': aw.aw_int (234), 'No': aw.aw_int (231)}
#print back result to test
for key in aw.aw_string (239):
print 'key=%s, value=%s' % (key, aw.aw_string (239)[key])
here are the first two lines of code to show what "aw" is
from ctypes import *
aw = CDLL("aw")
to explain what the numbers in the API calls are:
231 AW_OBJECT_NUMBER,
232 AW_OBJECT_X,
233 AW_OBJECT_Y,
234 AW_OBJECT_Z,
239 AW_OBJECT_DESCRIPTION,
231-234 are integers and 239 is a string
I deduce that you are using the Active Worlds SDK. It would save time to mention that in the first place in future questions.
I guess your goal is to create a top-level dictionary, where each key is the object description. Each value is another dictionary, storing many of the attributes of that object.
I took a quick look at the AW SDK documentation on the wiki and I don't see a way to ask the SDK for a list of attribute names, IDs, and types. So you will have to hard-code that information in your program somehow. Unless you need it elsewhere, it's simplest to just hard-code it where you create the dictionary, which is what you are already doing. To print it back out, just print the attribute dictionary's repr. I would probably format your method more like this:
def py_cell_object():
#object counter - unrelated to question
addtototal()
description = aw.aw_string(239)
if description.startswith("TDT3_"):
vars()[description] = {
'DESCRIPTION': description,
'X': aw.aw_int(232),
'Y': aw.aw_int(233),
'Z': aw.aw_int(234),
'NUMBER': aw.aw_int (231),
... etc for remaining attributes
}
print repr(vars()[description])
Some would argue that you should make named constants for the numbers 232, 233, 234, etc., but I see little reason to do that unless you need them in multiple places, or unless it's easy to generate them automatically from the SDK (for example, by parsing a .h file).
If the variables are defined in the local scope, it's as simple as:
obj_names = {}
while True:
varname = read_name()
if not varname: break
obj_names[varname] = locals()[varname]
This is actual code I am using in my production environment
hope it helps.
cveDict = {}
# StrVul is a python list holding list of vulnerabilities belonging to a report
report = Report.objects.get(pk=report_id)
vul = Vulnerability.objects.filter(report_id=report_id)
strVul = map(str, vul)
# fill up the python dict, += 1 if cvetype already exists
for cve in strVul:
i = Cve.objects.get(id=cve)
if i.vul_cvetype in cveDict.keys():
cveDict[i.vul_cvetype] += 1
else:
cveDict[i.vul_cvetype] = 1

Syntax for adding sequential objects to a list

Very beginner question but it is driving me mad. sample1, sample2 etc. are Pygame.mixer.sound objects.
sample_list = []
sample_list.append(sample1)
sample_list.append(sample2)
sample_list.append(sample3)
Is fine, but I want to do that using a for style loop, e.g.
for j in range(1, 3, 1):
sample_list.append(sample + j)
But that is trying to add a number to a sound object so isn't right. I can add the equivalent string by;
for j in range(1, 3, 1):
sample_list.append("sample" + str(j))
But that doesn't refer to the objects I want, just adds those strings.
I've tried must permutations of syntax I can think of but it is still alluding me!
Thanks.
Don't store the objects in variables in the first place; store them directly into a list, and then you will be able to index them by integer.
If the integer identifiers are sparse, use a dict indexed by integer.
I would recommend storing these in a dict to begin with. It is almost the same effect for you to reference by a name, but without the explicit object symbol for each:
samples = {
"sample1": Sample(),
"sample2": Sample()
}
samples['sample3'] = Sample()
This is the preferred approach when you have a dynamic number of objects you are creating and want to be able to grab them by a name later. You can store 100's of these in your dict without cluttering up your namespace.
And later if you are trying to apply this to your loop, you can reference the string names:
for i in xrange(1,4):
sample_list.append(samples["sample" + str(i)])
As a side note another way to get attributes by name when they live on some object is to use getattr. Assume you have this:
class Sampler(object):
pass
sampler = Sampler()
sampler.sample1 = Sample()
sampler.sample2 = Sample()
sampler.sample3 = Sample()
You can then reference by name via: getattr(sampler, "sample1")
Note: As mentioned in comments by #Marcin, if you don't care about having a string identifier to be able to look up your items, and they are just purely sequential by number, you can use this same approach but with a list. It depends on your needs.
It is possible you might want to end up doing something like:
samples = {
"bang1": Sample(),
"bang2": Sample(),
"bang3": Sample(),
"shot1": Sample(),
"shot2": Sample(),
...
}
... Which would then allow you to look up sequential subsets of those sounds.
You can dynamically load variables from the locals() mapping:
for j in range(1, 4):
sample_list.append(locals()["sample" + str(j)])
Generally, you want to avoid such tricks; find other ways to store your sample variables, in a mapping or a list for example.
Looks like the wrong approach, but nevertheless.
sample_list = [eval('sample' + str(i)) for i in range(1, 4)]

Set variables from variables?

I've got many, many strings, all formatted like this: "lot1", "lot2", "lot3"... What I'd like to do is use a function argument to determine which variable to use. Here's a pseudoexample:
def printlot(someInt):
print lot%i % (someInt)
Basically, I'd like to use multiple strings to form the name of another string to act with. This seems simple enough, but I haven't learned how to do it in my two years of Pythoning.
What nneonneo said is correct, but you're really going to want to use a dict explicitly. That is, you want to do this:
lot_data = {'lot1': 10, 'lot2': 20, 'lot3': 30}
i = 2
print lot_data['lot%d' % i]
Instead of this:
lot1 = 10
lot2 = 20
lot3 = 30
i = 2
print vars()['lot%d' % i]
You can access all visible variables as a dictionary using the vars builtin function:
vars()['lot%d' % someInt]
Different scopes can be accessed with globals or locals.
Note, however, that this is generally considered "unpythonic" behaviour. Instead of creating many similarly-named variables, a more Pythonic approach would be to make a list or dictionary.

best way to create this dict in python

this is my code :
vars_ = {
'attackUp':attackUp,'defenceUp':defenceUp,'magicUp':magicUp,'attType':attType,'weightDown':weightDown,
'accAttackSword':accAttackSword,'accAttackSaber':accAttackSaber,'accAttackAx':accAttackAx,
'accAttackHammer':accAttackHammer,'accAttackSpear':accAttackSpear,'accAttackFight':accAttackFight,
'accAttackBow':accAttackBow,'accAttackMagicGun':accAttackMagicGun,'accAttackMagic':accAttackMagic,
'mStrInstrument':mStrInstrument,'mStrCharms':mStrCharms,'accDefencePhy':accDefencePhy,
'accDefenceMag':accDefenceMag,'accWeight':accWeight,'bookTurn':bookTurn,'bookAttackPhy':bookAttackPhy,
'bookAttackMag':bookAttackMag,'bookStrInstrument':bookStrInstrument,'bookStrCharms':bookStrCharms,
'bookDefencePhy':bookDefencePhy,'bookDefenceMag':bookDefenceMag,'bookWeight':bookWeight,'name':name,
'plvl':plvl,'str':str,'ski':ski,'mag':mag,'spd':spd,'locX':locX,'locY':locY,'wName':wName,
'wAttack':wAttack,'wDefence':wDefence,'wWeight':wWeight,'wType':wType,'target':target,'title':title,
'uname':uname,'cUrl':cUrl,'mbCnt':mbCnt
}
oh my god , I spent a lot of time on this work , and maybe have more Variable to be added later ,
any easy way to do this ,
thanks
I would stop and consider why you are doing this. I can't help but think its not necessary.
Even if you decide this is necessary (which i doubt) - You are pretty much recreating globals(). Type that into your interpretter and see if you still want to do this.
Organize it further like senderle suggested in your other post. And maybe post a broader question with help for organizing your project.
The first thing I would do is reformat that dictionary so there is one entry per line:
vars_ = {
'attackUp' : attackUp,
'defenceUp' : defenceUp,
'magicUp' : magicUp,
'attType' : attType,
'weightDown': weightDown,
# and so on
}
I have also lined up the columns so the whole list reads more easily.
You could make an array of variable names and pull them out of the locals dictionary.
x, y, z = 5, 10, 20
l = locals()
d = {}
for v in ['x', 'y', 'z']:
d[v] = l[v]
# d = {'y': 10, 'x': 5, 'z': 20}
locals might work on it's own too if you're just wanting to look it up as a string.
attUp = locals()['attackUp']
I totally agree with #miku - look at how you are using the values and seriously refactor.
For example, a Character has Attributes (physical_attack, physical_defence, magic_attack, magic_defence, weight, speed) and Items; Weapons are Items, Swords and Axes and Spears and Bows are Weapons, a Saber is a Sword. Unarmed is a special default Weapon. Charms are Items, but apparently Books and StringedInstruments are Weapons?? Items have Attributes which are added to a Character's Attributes while equipped. Character also has level, location, target, and an accuracy rating for each weapon type (can a Weapon have an accuracy-modifier?).
If you break it down into a class hierarchy this way, it should be much easier to keep track of what you are doing.

Categories