best way to create this dict in python - 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.

Related

If I have 2 lists in a dictionary, how to append both of them at once?

self.W = {}
self.W[A] = {'x':[], 'y':[]}
I want to do the following:
self.W[A]['x'].append(X)
and:
self.W[A]['y'].append(Y),
at once.
How to do both in one command?
Edit:
Let me write it in more clear way:
WEAPONS = {}
WEAPONS['launcher'] = {'idle_img' : [ "pic1.png", "pic2.png", "pic3.png"],
'shoot_img' : ['img1.png', 'img2.png', 'img3.png'],
WEAPONS['pistol'] = {'idle_img' : [ "another_pic1.png", "another_pic2.png",'another_pic3'],
'shoot_img' : ['another_img1.png', 'you know.png', 'abcxyz.png']}
now I have another dict:
self.another_dict = {}
self.another_dict['launcher'] = {'idle_img' : [],
'shoot_img' : [],
self.another_dict['pistol'] = {'idle_img' : [],
'shoot_img' : []}
Now, I want to add those images in WEAPONS['pistol']['idle_img'] to self.another_dict['pistol']['idle_img']
also do it with ['shoot_img'] (and a lot of ['something_img'] like that too).I can do that one by one :
for l in WEAPONS:
for i in self.WEAPONS[l]['idle_img']:
self.another_dict[l]['idle_img'].append(i)
but that kind of long if I do that for all those [' _img']
So, I assume there must be a way to do them at once, or there will be a lot of writing.
I think you might find dict().from_keys() helpful.
W = {}.fromkeys(['x', 'y'], [])
W['x'].append('hello')
{'x': ['hello'], 'y': ['hello']}
It creates a dictionary with the provided keys, and their default values are the same object (if mutable). So, appending one will append the other. But be careful, they really do point to the same object so you'll have to do extra steps to treat them separately in the future.
ah damn, I cant believe I use loop twice but dont use it again. here is how I solve it:
for l in WEAPONS:
for t in self.another_dict[l]
for i in self.WEAPONS[l][t]:
self.another_dict[l][t].append(i)
thx for all the answer

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

Parse string with three-level delimitation into dictionary

I've found how to split a delimited string into key:value pairs in a dictionary elsewhere, but I have an incoming string that also includes two parameters that amount to dictionaries themselves: parameters with one or three key:value pairs inside:
clientid=b59694bf-c7c1-4a3a-8cd5-6dad69f4abb0&keyid=987654321&userdata=ip:192.168.10.10,deviceid:1234,optdata:75BCD15&md=AMT-Cam:avatar&playbackmode=st&ver=6&sessionid=&mk=PC&junketid=1342177342&version=6.7.8.9012
Obviously these are dummy parameters to obfuscate proprietary code, here. I'd like to dump all this into a dictionary with the userdata and md keys' values being dictionaries themselves:
requestdict {'clientid' : 'b59694bf-c7c1-4a3a-8cd5-6dad69f4abb0', 'keyid' : '987654321', 'userdata' : {'ip' : '192.168.10.10', 'deviceid' : '1234', 'optdata' : '75BCD15'}, 'md' : {'Cam' : 'avatar'}, 'playbackmode' : 'st', 'ver' : '6', 'sessionid' : '', 'mk' : 'PC', 'junketid' : '1342177342', 'version' : '6.7.8.9012'}
Can I take the slick two-level delimitation parsing command that I've found:
requestDict = dict(line.split('=') for line in clientRequest.split('&'))
and add a third level to it to handle & preserve the 2nd-level dictionaries? What would the syntax be? If not, I suppose I'll have to split by & and then check & handle splits that contain : but even then I can't figure out the syntax. Can someone help? Thanks!
I basically took Kyle's answer and made it more future-friendly:
def dictelem(input):
parts = input.split('&')
listing = [part.split('=') for part in parts]
result = {}
for entry in listing:
head, tail = entry[0], ''.join(entry[1:])
if ':' in tail:
entries = tail.split(',')
result.update({ head : dict(e.split(':') for e in entries) })
else:
result.update({head: tail})
return result
Here's a two-liner that does what I think you want:
dictelem = lambda x: x if ':' not in x[1] else [x[0],dict(y.split(':') for y in x[1].split(','))]
a = dict(dictelem(x.split('=')) for x in input.split('&'))
Can I take the slick two-level delimitation parsing command that I've found:
requestDict = dict(line.split('=') for line in clientRequest.split('&'))
and add a third level to it to handle & preserve the 2nd-level dictionaries?
Of course you can, but (a) you probably don't want to, because nested comprehensions beyond two levels tend to get unreadable, and (b) this super-simple syntax won't work for cases like yours, where only some of the data can be turned into a dict.
For example, what should happen with 'PC'? Do you want to make that into {'PC': None}? Or maybe the set {'PC'}? Or the list ['PC']? Or just leave it alone? You have to decide, and write the logic for that, and trying to write it as an expression will make your decision very hard to read.
So, let's put that logic in a separate function:
def parseCommasAndColons(s):
bits = [bit.split(':') for bit in s.split(',')]
try:
return dict(bits)
except ValueError:
return bits
This will return a dict like {'ip': '192.168.10.10', 'deviceid': '1234', 'optdata': '75BCD15'} or {'AMT-Cam': 'avatar'} for cases where each comma-separated component has a colon inside it, but a list like ['1342177342'] for cases where any of them don't.
Even this may be a little too clever; I might make the "is this in dictionary format" check more explicit instead of just trying to convert the list of lists and see what happens.
Either way, how would you put that back into your original comprehension?
Well, you want to call it on the value in the line.split('='). So let's add a function for that:
def parseCommasAndColonsForValue(keyvalue):
if len(keyvalue) == 2:
return keyvalue[0], parseCommasAndColons(keyvalue[1])
else:
return keyvalue
requestDict = dict(parseCommasAndColonsForValue(line.split('='))
for line in clientRequest.split('&'))
One last thing: Unless you need to run on older versions of Python, you shouldn't often be calling dict on a generator expression. If it can be rewritten as a dictionary comprehension, it will almost certainly be clearer that way, and if it can't be rewritten as a dictionary comprehension, it probably shouldn't be a 1-liner expression in the first place.
Of course breaking expressions up into separate expressions, turning some of them into statements or even functions, and naming them does make your code longer—but that doesn't necessarily mean worse. About half of the Zen of Python (import this) is devoted to explaining why. Or one quote from Guido: "Python is a bad language for code golf, on purpose."
If you really want to know what it would look like, let's break it into two steps:
>>> {k: [bit2.split(':') for bit2 in v.split(',')] for k, v in (bit.split('=') for bit in s.split('&'))}
{'clientid': [['b59694bf-c7c1-4a3a-8cd5-6dad69f4abb0']],
'junketid': [['1342177342']],
'keyid': [['987654321']],
'md': [['AMT-Cam', 'avatar']],
'mk': [['PC']],
'playbackmode': [['st']],
'sessionid': [['']],
'userdata': [['ip', '192.168.10.10'],
['deviceid', '1234'],
['optdata', '75BCD15']],
'ver': [['6']],
'version': [['6.7.8.9012']]}
That illustrates why you can't just add a dict call for the inner level—because most of those things aren't actually dictionaries, because they had no colons. If you changed that, then it would just be this:
{k: dict(bit2.split(':') for bit2 in v.split(',')) for k, v in (bit.split('=') for bit in s.split('&'))}
I don't think that's very readable, and I doubt most Python programmers would. Reading it 6 months from now and trying to figure out what I meant would take a lot more effort than writing it did.
And trying to debug it will not be fun. What happens if you run that on your input, with missing colons? ValueError: dictionary update sequence element #0 has length 1; 2 is required. Which sequence? No idea. You have to break it down step by step to see what doesn't work. That's no fun.
So, hopefully that illustrates why you don't want to do this.

getting Python variable name in runtime

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)

question about managing values with multiple subvalues in python 3k

I have a question reguarding how I would perform the following task in python.
(I use python 3k)
what I have are several variables which can yield further variables on top of those
and each of those have even more variables
for example:
a generic name would be
item_version_type =
where each part (item, version, and type) refer to different variables(here there are 3 for each)
item = item_a, item_b, item_c
version = range(1,3)
itemtype = itemtype_a, itemtype_b, itemtype_c
simply listing each name and defining it is annoying:
itema_ver1_typea =
itemb_ver1_typea =
itemc_ver1_typea =
itema_ver2_typea =
etc.
etc.
etc.
especially when I have something where one variable is dependent on something else
for example:
if value == True:
version = ver + 1
and to top it off this whole example is rather simply compared to what I'm actually
working with.
one thing I am curious about is using multiple "." type of classes such as:
item.version.type
I know that this can be done
I just can't figure out how to get a class with more than one dot
either that or if anyone can point me to a better method
Thanks for help.
Grouping of data like this can be done in three ways in Python.
First way is tuples:
myvariable = ('Sammalamma', 1, 'Text')
The second way is a dictionary:
myvariable = {'value': 'Sammalamma', 'version': 1, 'type': 'Text'}
And the third way is a class:
class MyClass(object):
def __init__(self, value, version, type):
self.value = value
self.version = version
self.type = type
>>> myvariable = MyClass('Sammalamma', 1, 'Text')
>>> myvariable.value
'Sammalamma'
>>> myvariable.version
1
>>> myvariable.type
'Text'
Which one to use in each case is up to you, although in this case I would claim that the tuple doesn't seem to be the best choice, I would go for a dictionary or a class.
None of this is unique to Python 3, it works in any version of Python.
In addition to #Lennart Regebro's answer if items are immutable:
import collections
Item = collections.namedtuple('Item', 'value version type')
items = [Item(val, 'ver'+ver, t)
for val in 'abc' for ver in '12' for t in ['typea']]
print(items[0])
# -> Item(value='a', version='ver1', type='typea')
item = items[1]
print(item.value, item.type)
# -> b typea
sorry for posting this here instead of the comments but I have no clue how to work the site here.
for clarification
what I need is basically to have be able to get an output of said such as where
I could take a broad area (item) narrow it further (version) and even further (type as in type of item like lets say types are spoon, knife, fork)
or a better description is like arm.left.lower = lower left arm
where I could also have like leg.left.lower
so I could have arm.both.upper to get both left and right upper arms
where a value would be assigned to both.
what I need is to be able to do truth tests etc. and have it return the allowable values
such as
if leg == True
output is --> leg.both.lower, leg.both.upper, leg.left.upper leg.right.upper, etc., etc., etc.
if upper == True
output is --> leg.both.upper, leg.left.upper, etc., etc., etc.
hopefully that helps
Basically I get how to get something like item.version but how do I get something
like item.version.type
I need to have it to be more specific than just item.version
I need to be able to tell if item is this and version is that then type will be x
like
item.version.type
if version == 3:
item.version = spoon.3.bent
#which is different from
if version == 2:
item.version.type = spoon.2.bent

Categories