I am new in Python.
I am trying to create many ordereddict,but because I am filling it out in messed sequence I had to create a function to pass in the normal dict to get the order I want.
info = dict()
info['age'] = 3
...
keys=['id','name','age','ck_id','image']
def fix_order(my_dict):
new_queue = OrderedDict()
for k in keys:
new_queue[k] = item[k]
return new_queue
What I want to do is to create a simple class which already has the order I want no matter the sequence of filling it.
I checked this questionHow to create an OrderedDict in Python?, but this assumes I have the values first hand.
i.e what I want info = my_dict() #already has the sequence (order) built in
As I understand you want to have a data structure that gives you the same operations as dict, but if iterate over gives items in a precise order.
If this is the case you can override the methods that gives out iterables: the __iter__ method, the key method, the values method and the items method (maybe there are others which I can't remember)
There is a basic class you can start off. (I.e this will only iterate over the elements you specified, but probably you want to extend to iterate over the other elements, too)
from collections import UserDict
class MyDict(UserDict):
def __init__(self, *args, **kwargs):
self.order = kwargs.pop('order')
super().__init__(*args)
def change_order(self, order: list):
self.order = order
def __iter__(self):
for key in self.order:
if key in self:
yield key
def keys(self):
for key in self.order:
if key in self:
yield key
def values(self):
for key in self.order:
if key in self:
yield self[key]
def items(self):
for key in self.order:
if key in self:
yield key, self[key]
There is a test:
d = MyDict({"b" : 2, "c": 3, "a": 1}, order=["a","b","c"])
print(d)
for k in d:
print(k, end=" ")
#a b c
print()
for k in d.keys():
print(k, end=" ")
#a b c
print()
for v in d.values():
print(v, end=" ")
#1 2 3
print()
for k, v in d.items():
print(f"{k}-{v}", end=" ")
#a-1 b-2 c-3
You can override __repr__ and __str__ if you want your dictionary to be converted in string (and printed) in the order you want, too
Related
I am trying to provide a function as the default argument for the dictionary's get function, like this
def run():
print "RUNNING"
test = {'store':1}
test.get('store', run())
However, when this is run, it displays the following output:
RUNNING
1
so my question is, as the title says, is there a way to provide a callable as the default value for the get method without it being called if the key exists?
Another option, assuming you don't intend to store falsy values in your dictionary:
test.get('store') or run()
In python, the or operator does not evaluate arguments that are not needed (it short-circuits)
If you do need to support falsy values, then you can use get_or_run(test, 'store', run) where:
def get_or_run(d, k, f):
sentinel = object() # guaranteed not to be in d
v = d.get(k, sentinel)
return f() if v is sentinel else v
See the discussion in the answers and comments of dict.get() method returns a pointer. You have to break it into two steps.
Your options are:
Use a defaultdict with the callable if you always want that value as the default, and want to store it in the dict.
Use a conditional expression:
item = test['store'] if 'store' in test else run()
Use try / except:
try:
item = test['store']
except KeyError:
item = run()
Use get:
item = test.get('store')
if item is None:
item = run()
And variations on those themes.
glglgl shows a way to subclass defaultdict, you can also just subclass dict for some situations:
def run():
print "RUNNING"
return 1
class dict_nokeyerror(dict):
def __missing__(self, key):
return run()
test = dict_nokeyerror()
print test['a']
# RUNNING
# 1
Subclassing only really makes sense if you always want the dict to have some nonstandard behavior; if you generally want it to behave like a normal dict and just want a lazy get in one place, use one of my methods 2-4.
I suppose you want to have the callable applied only if the key does not exist.
There are several approaches to do so.
One would be to use a defaultdict, which calls run() if key is missing.
from collections import defaultdict
def run():
print "RUNNING"
test = {'store':1}
test.get('store', run())
test = defaultdict(run, store=1) # provides a value for store
test['store'] # gets 1
test['runthatstuff'] # gets None
Another, rather ugly one, one would be to only save callables in the dict which return the apropriate value.
test = {'store': lambda:1}
test.get('store', run)() # -> 1
test.get('runrun', run)() # -> None, prints "RUNNING".
If you want to have the return value depend on the missing key, you have to subclass defaultdict:
class mydefaultdict(defaultdict):
def __missing__(self, key):
val = self[key] = self.default_factory(key)
return val
d = mydefaultdict(lambda k: k*k)
d[10] # yields 100
#mydefaultdict # decorators are fine
def d2(key):
return -key
d2[5] # yields -5
And if you want not to add this value to the dict for the next call, you have a
def __missing__(self, key): return self.default_factory(key)
instead which calls the default factory every time a key: value pair was not explicitly added.
If you only know what the callable is likely to be at he get call site you could subclass dict something like this
class MyDict(dict):
def get_callable(self,key,func,*args,**kwargs):
'''Like ordinary get but uses a callable to
generate the default value'''
if key not in self:
val = func(*args,**kwargs)
else:
val = self[key]
return val
This can then be used like so:-
>>> d = MyDict()
>>> d.get_callable(1,complex,2,3)
(2+3j)
>>> d[1] = 2
>>> d.get_callable(1,complex,2,3)
2
>>> def run(): print "run"
>>> repr(d.get_callable(1,run))
'2'
>>> repr(d.get_callable(2,run))
run
'None'
This is probably most useful when the callable is expensive to compute.
I have a util directory in my project with qt.py, general.py, geom.py, etc. In general.py I have a bunch of python tools like the one you need:
# Use whenever you need a lambda default
def dictGet(dict_, key, default):
if key not in dict_:
return default()
return dict_[key]
Add *args, **kwargs if you want to support calling default more than once with differing args:
def dictGet(dict_, key, default, *args, **kwargs):
if key not in dict_:
return default(*args, **kwargs)
return dict_[key]
Here's what I use:
def lazy_get(d, k, f):
return d[k] if k in d else f(k)
The fallback function f takes the key as an argument, e.g.
lazy_get({'a': 13}, 'a', lambda k: k) # --> 13
lazy_get({'a': 13}, 'b', lambda k: k) # --> 'b'
You would obviously use a more meaningful fallback function, but this illustrates the flexibility of lazy_get.
Here's what the function looks like with type annotation:
from typing import Callable, Mapping, TypeVar
K = TypeVar('K')
V = TypeVar('V')
def lazy_get(d: Mapping[K, V], k: K, f: Callable[[K], V]) -> V:
return d[k] if k in d else f(k)
I have an object class that I use as a key into a python dictionary.
from dataclasses import dataclass
#dataclass
class CompWord:
c: str
length: int
def __hash__(self):
return hash(self.c)
def __eq__(self, other):
return self.c == other
_ = lambda: defaultdict(_)
d = _()
for compword1 in [CompWord('a', 1), CompWord('b', 2)]:
key = d[compword1]
for compword2 in [CompWord('c', 1), CompWord('d', 2)]:
key = key[compword2]
at this point, d is
CompWord(c='a', length=1)
CompWord(c='c', length=1)
CompWord(c='d', length=2)
CompWord(c='b', length=2)
CompWord(c='c', length=1)
CompWord(c='d', length=2)
I want to update the key in this dictionary if I come across it again only if the length of CompWord is greater than length of key that is already in the dictionary. For example, CompWord(a, 4) > CompWord(a, 1), so I want to update this key with CompWord(a, 4), while also preserving the nested dictionaries under CompWord(a, 1).
Expected output after I update CompWord(a, 1) to Compword(a, 4)
c_word = CompWord('a', 4)
if c_word in d:
# update d[c_word] with new key CompWord(c_word.length, <old length 1>)
CompWord(c='a', length=4)
CompWord(c='c', length=1)
CompWord(c='d', length=2)
CompWord(c='b', length=2)
CompWord(c='c', length=1)
CompWord(c='d', length=2)
I need to able to reference the length of the old key above which is 1, but I am not sure how I get access to it.
You've edited your post a bunch since I started writing my answer, and I don't really feel like reading through your post again...
I'd suggest implementing __lt__ and using max():
#dataclass
class CompWord:
c: str
length: int
def __hash__(self):
return hash(self.c)
def __eq__(self, other):
return self.c == other
def __lt__(self, other):
return self.length < other.length
Now accumulate keys to replace:
keys_to_replace = []
for key in d:
if key == c_word:
keys_to_replace.append((key, max(key, c_word)))
Now replace keys:
for old_key, new_key in keys_to_replace:
d[new_key] = d.pop(old_key)
Also, I'd recommend returning self.c == other.c in your __eq__ as that is more explicit.
EDIT:
I suggest implementing a recursive key_replacer() function if you want to drill down into a deeply nested dictionary, as your edits suggest.
I also think it might not be a good idea to __hash__ and __eq__ on only one of the values of your dataclass. That seems like a recipe for headaches during debugging.
def __hash__(self):
"""Creating hash for item"""
if isinstance(self.get_values(), (tuple, list)):
return tuple([self.__hash__() for e in self.get_values()])
elif not isinstance(self.get_values(), dict):
return hash(self.get_values())
new_o = copy.deepcopy(self.get_values())
for k, v in new_o.items():
new_o[k] = self.__hash__()
I have custom recursive hash function. Self.get_values() contains a list of dicts.I want to iterate every object of self and make hash of it. The problem is that then i call new_o[k] =self.__hash__() for example,
i want something like self.__ hash__(v), the v could be a list and i want to call my custom hash function.
Instead of this, it calls hash again for whole self and i get recursion error. I can't do like new_o[k] = hash(v), because it goes for hash function of this type.
When iterating over the list/tuple or over the items, you need to call the hash method on the object of the iteration you keep calling on self which the instance on which you call the method
[e.__hash__() for e in self.get_values()] # for list/tuple
new_o[k] = v.__hash__() # for k,v
To give :
def __hash__(self):
"""Creating hash for item"""
if isinstance(self.get_values(), (tuple, list)):
return tuple([e.__hash__() for e in self.get_values()])
elif not isinstance(self.get_values(), dict):
return hash(self.get_values())
new_o = copy.deepcopy(self.get_values())
for k, v in new_o.items():
if v: # handle empty and None
new_o[k] = v.__hash__()
Let's say I have a defaultdict in the following form:
theta = defaultdict(float)
The key consists of a tuple of strings i.e. (label, word), and the associated value is the probability that the given word fits the given label (part of speech tagging).
For example, the word 'stand' could be a noun or a verb. So I could do something like:
theta[('NOUN', 'stand')] = 0.4
theta[('VERB', 'stand')] = 0.6
theta[('ADJ', 'stand')] = 0.0
and so on for the remaining parts of speech labels.
What I need to do is have the dictionary return a value of 1 by default if it is invoked with a word that it does not contain and the associated label is 'NOUN', and return 0 for all other associated labels. For example:
value = theta[('NOUN', 'wordthatdoesntexist')] # this should be 1
value = theta[('VERB', 'wordthatdoesntexist')] # this should be 0
How can I do this? Can I do it in the initialization step, using lambda? Or is there some other way?
A defaultdict can't do that; the default factory doesn't have access to the key. You'd have to write your own dict subclass, using the __missing__ hook dicts look for when you try to access a missing key:
class SomeAppropriateName(dict):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def __missing__(self, key):
val = 1.0 if key[0] == 'NOUN' else 0.0
# Uncomment the following line if you want to add the value to the dict
# self[key] = val
return val
You can use the setdefault() method of dict:
d.setdefault(u, int(u[0] == "NOUN"))
If u is found in d, then setdefault returns d[u]. Otherwise, it is inserted in the dict, with the value provided as second argument.
I am trying to determine if a specific key and value pair exist in a dictionary; however, if I use the contains or has-key method, it only checks for the key. I need it to check both the key and the specific value. Some background:
We have a total of 4 dictionaries: one for A, B, CompareList, and ChangeList. Once A is initialized, I put A's contents into CompareList (I would compare them directly; but A and B are double hash tables. And I've tried all of the methods here; but none of them work for me). So once we put A into CompareList, I compare it with the ObjectAttributes dictionary in B to see if anything changed. So for example, B may have the key,value pairs shape:circle and fill:no. If CompareList had shape:circle and fill:yes, then I want only fill:yes to be ChangeList. The problem lies in the "if attributes.getName() not in self.CompareList:" line. Here is the code; I am running it on Python 2.7.8. Thanks in advance for any help!!
class ObjectSemanticNetwork:
def __init__(self):
self.ObjectNames = {}
self.ObjectAttributes = {}
def setName(self, name):
self.ObjectNames[name] = self.ObjectAttributes
def setData(self, name, attribute):
self.ObjectAttributes[name] = attribute
def checkData(self, key):
print(key)
for key, value in self.ObjectAttributes.iteritems():
print(key)
print(value)
print("\n")
class Agent:
(self):
self.CompareList = {}
self.ChangeListAB = {}
self.ChangeListCD = {}
def addToCompareList(self, name, value):
self.CompareList[name] = value
def addToChangeListAB(self, name, value):
self.ChangeListAB[name] = value
def addToChangeListCD(self, name, value):
self.ChangeListCD[name] = value
def CheckList(self, List, ListName):
print '-------------------------',ListName,'--------------------------------'
for key, value in List.iteritems():
print(key)
print(value)
def Solve(self,problem):
OSNAB = ObjectSemanticNetwork()
for object in problem.getFigures().get("A").getObjects():
for attributes in object.getAttributes():
self.addToCompareList(attributes.getName(), attributes.getValue())
OSNAB.ObjectNames["A"] = OSNAB.setData(attributes.getName(), attributes.getValue())
#OSNAB.checkData("A")
self.CheckList(self.CompareList,"CompareList")
for object in problem.getFigures().get("B").getObjects():
for attributes in object.getAttributes():
if attributes.getName() not in self.CompareList:
self.addToChangeListAB(attributes.getName(), attributes.getValue())
OSNAB.ObjectNames["B"] = OSNAB.setData(attributes.getName(), attributes.getValue())
# OSNAB.checkData("B")
self.CheckList(self.ChangeListAB,"ChangeList")
OSNCD = ObjectSemanticNetwork()
for object in problem.getFigures().get("C").getObjects():
for attributes in object.getAttributes():
OSNCD.ObjectNames["C"] = OSNCD.setData(attributes.getName(), attributes.getValue())
# OSNCD.checkData("C")
for object in problem.getFigures().get("1").getObjects():
for attributes in object.getAttributes():
OSNCD.ObjectNames["D"] = OSNCD.setData(attributes.getName(), attributes.getValue())
# OSNCD.checkData("D")
return "6"
Use
if key in d and d[key] == value:
Or (only in Python 3)
if (key, value) in d.items():
In Python 3 d.items() returns a Dictionary view object, which supports fast membership testing. In Python 2 d.items() returns a list, which is both slow to create and slow to to test membership. Python 2.7 is a special case where you can use d.viewitems() and get the same thing that you get with d.items() in Python 3.
Edit: In a comment you indicate that for performance reasons you prefer checkKeyValuePairExistence over key in d and d[key] == value. Below are some timings showing that checkKeyValuePairExistence is always slower (by about 2x on my system when the key-value pair is present 16x when it is not). I also tested larger and smaller dictionaries and found little variation in the timings.
>>> import random
>>> from timeit import timeit
>>> def checkKeyValuePairExistence(dic, key, value):
... try:
... return dic[key] == value
... except KeyError:
... return False
...
>>> d = {random.randint(0, 100000):random.randint(0, 100000) for i in range(1000)}
>>> setup = 'from __main__ import k, d, v, checkKeyValuePairExistence'
>>> test_try_except = 'checkKeyValuePairExistence(d, k, v)'
>>> test_k_in_d_and = 'k in d and d[k] == v'
>>> k, v = random.choice(d.items()) # to test if found
>>> timeit(test_try_except, setup=setup)
0.1984054392365806
>>> timeit(test_k_in_d_and, setup=setup)
0.10442071140778353
>>> k = -1 # test if not found
>>> timeit(test_try_except, setup=setup)
1.2896073903002616
>>> timeit(test_k_in_d_and, setup=setup)
0.07827843747497809
How about this function:
def checkKeyValuePairExistence(dic, key, value):
try:
return dic[key] == value
except KeyError:
return False
If you are using another type of dictionary other then the one python offers (I'm sorry, I couldnt understand from your post if you are using it or not) then let me know and i'll try to give your another solution
Why not just do this:
a = {1:'a', 2:'b'}
b = (1, 'a')
print b in a.iteritems() # prints True