kkumer wrote:
I have to merge two dictionaries into one, and in
a "shallow" way: changing items should be possible
by operating either on two parents or on a
new dictionary. I am open to suggestions how
to do this (values are always numbers, BTW), but
I tried to do it by creating a dict-like class that just
forwards all calls to the two parent dicts, see below.
It works, but one important thing is missing. I
am not able to expand new dictionary with
double-star operator ** to use it as a
set of keyword arguments of a function.
I googled a bit, but was unable to find what
property must an object have to be correctly
treated by **.
I hope the following code is self-explanatory:
------------------------------------
import itertools
class hubDict(dict):
"""Merges two dictionaries, but not actually but just by forwarding."""
def __init__(self, da, db):
self.d1 = da
self.d2 = db
def __getitem__(self, name):
if self.d1.has_key(name):
return self.d1[name]
else:
return self.d2[name]
def __setitem__(self, name, value):
if self.d1.has_key(name):
self.d1[name] = value
else:
self.d2[name] = value
def __iter__(self):
return itertools.chain(self.d1.__iter__(), self.d2.__iter__())
def has_key(self, name):
if self.d1.has_key(name) or self.d2.has_key(name):
return True
else:
return False
def keys(self):
return self.d1.keys() + self.d2.keys()
def items(self):
return self.d1.items() + self.d2.items()
def iteritems(self):
return itertools.chain(self.d1.iteritems(), self.d2.iteritems())
def iterkeys(self):
return itertools.chain(self.d1.iterkeys(), self.d2.iterkeys())
def itervalues(self):
return itertools.chain(self.d1.itervalues(), self.d2.itervalues())
def copy(self):
print "Can't copy hubDict yet!!!"
def update(self, d):
for key in d:
self.__setitem__(key, d[key])
def popitem(self):
try:
return self.d1.popitem()
except KeyError:
return self.d2.popitem()
def __repr__(self):
return 'First: %s\nSecond: %s' % (
self.d1.__repr__(), self.d2.__repr__())
# Trying it now:
da = {'a':1}
db = {'b':2}
dh = hubDict(da, db)
def kwa(**kwargs): print kwargs
#OK
kwa(**da)
#not OK: prints empty dict
kwa(**dh)
import itertools
class hubDict(dict):
"""Merges two dictionaries, but not actually but just by forwarding."""
def __init__(self, da, db):
self.d1 = da
self.d2 = db
def __getitem__(self, name):
if self.d1.has_key(name):
return self.d1[name]
else:
return self.d2[name]
def __setitem__(self, name, value):
if self.d1.has_key(name):
self.d1[name] = value
else:
self.d2[name] = value
def __iter__(self):
return itertools.chain(self.d1.__iter__(), self.d2.__iter__())
def has_key(self, name):
if self.d1.has_key(name) or self.d2.has_key(name):
return True
else:
return False
def keys(self):
return self.d1.keys() + self.d2.keys()
def items(self):
return self.d1.items() + self.d2.items()
def iteritems(self):
return itertools.chain(self.d1.iteritems(), self.d2.iteritems())
def iterkeys(self):
return itertools.chain(self.d1.iterkeys(), self.d2.iterkeys())
def itervalues(self):
return itertools.chain(self.d1.itervalues(), self.d2.itervalues())
def copy(self):
print "Can't copy hubDict yet!!!"
def update(self, d):
for key in d:
self.__setitem__(key, d[key])
def popitem(self):
try:
return self.d1.popitem()
except KeyError:
return self.d2.popitem()
def __repr__(self):
return 'First: %s\nSecond: %s' % (
self.d1.__repr__(), self.d2.__repr__())
def __len__(self):
return self.d1.__len__() + self.d2.__len__()
# Trying it now:
da = {'a':1}
db = {'b':2}
dh = hubDict(da, db)
def kwa(**kwargs): print kwargs
#OK
kwa(**da)
#not OK: prints empty dict
kwa(**dh)
From the help on "Container types",
>>The UserDict <../library/userdict.html#module-UserDict> module
provides a DictMixin class to help create those methods from a base set
of __getitem__() <#object.__getitem__>, __setitem__()
<#object.__setitem__>, __delitem__() <#object.__delitem__>, and keys().
<<
and
>>It is recommended that both mappings and sequences implement the
__contains__() <#object.__contains__> method to allow efficient use of
the in operator; for mappings, in should be equivalent of has_key(); for
sequences, it should search through the values. It is further
recommended that both mappings and sequences implement the __iter__()
<#object.__iter__> method to allow efficient iteration through the
container; for mappings, __iter__() <#object.__iter__> should be the
same as iterkeys(); for sequences, it should iterate through the values.
<<
I'd guess that the ** operator calls one or more of these special
methods directly, rather than calling the equivalent regular methods.
DaveA
--
http://mail.python.org/mailman/listinfo/python-list