Which objects are expanded by double-star ** operator?

Thomas Jollans thomas at jollans.com
Mon Jun 7 16:33:30 EDT 2010


On 06/07/2010 10:17 PM, 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 **.
>   
My guess would be that this only works with dicts, and uses the internal
representation of the dict, not the python-defined methods.
I don't know what you want to do, but you might be better off creating a
special "mergeabledict" type for the parents, and then allow them to
connect, actually copying all items over. Though it might be best just
to use one single dict ;-)

> 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)
>
>   




More information about the Python-list mailing list