From: Terry Reedy on
The answer depends on the version:
in 2.5 "If the syntax "**expression" appears in the function call,
"expression" must evaluate to a (subclass of) dictionary, "
in 3.1 "If the syntax **expression appears in the function call,
expression must evaluate to a mapping,"

ReferenceManual.Epressions.Primaries.Calls

Terry Jan Reedy

From: Ian Kelly on
On Mon, Jun 7, 2010 at 4:03 PM, Peter Otten <__peter__(a)web.de> wrote:
> The following experiment shows that you only need to implement a keys() and
> __getitem__() method.
>
> $ cat kw.py
> class A(object):
>    def keys(self): return list("ab")
>    def __getitem__(self, key):
>        return 42
>
> def f(**kw):
>    print(kw)
>
> f(**A())
> $ python kw.py
> {'a': 42, 'b': 42}

This seems to require Python 2.6. With 2.5, you get:

Traceback (most recent call last):
File "kw.py", line 9, in <module>
f(**A())
TypeError: f() argument after ** must be a dictionary

Cheers,
Ian
From: Terry Reedy on
On 6/7/2010 6:03 PM, Peter Otten wrote:
> 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 **.
>
> The following experiment shows that you only need to implement a keys() and
> __getitem__() method.
>
> $ cat kw.py
> class A(object):
> def keys(self): return list("ab")
> def __getitem__(self, key):
> return 42
>
> def f(**kw):
> print(kw)
>
> f(**A())
> $ python kw.py
> {'a': 42, 'b': 42}
>
> However, if you have A inherit from dict...
>
> $ cat kwd.py
> class A(dict):
> def keys(self): return list("ab")
> def __getitem__(self, key):
> return 42
>
> def f(**kw):
> print(kw)
>
> f(**A())
> $ python kwd.py
> {}
>
> it stops working -- probably a side-effect of some optimization.
> So if you change your hubDict's base class from dict to object you should
> get the desired behaviour.

In 2.6, the requirement changed from '(subclass of) dictionary' to
'mapping' so this is a bit strange. It sort of looks like a bug. I will
test with 3.1 tomorrow (later today, actually).

tjr



From: Kresimir Kumericki on
Peter Otten <__peter__(a)web.de> wrote:
> 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 **.
>
> The following experiment shows that you only need to implement a keys() and
> __getitem__() method.
>
> $ cat kw.py
> class A(object):
> def keys(self): return list("ab")
> def __getitem__(self, key):
> return 42
>
> def f(**kw):
> print(kw)
>
> f(**A())
> $ python kw.py
> {'a': 42, 'b': 42}
>
> However, if you have A inherit from dict...
>
> $ cat kwd.py
> class A(dict):
> def keys(self): return list("ab")
> def __getitem__(self, key):
> return 42
>
> def f(**kw):
> print(kw)
>
> f(**A())
> $ python kwd.py
> {}
>
> it stops working -- probably a side-effect of some optimization.
> So if you change your hubDict's base class from dict to object you should
> get the desired behaviour.
>
> Peter

--
Kresimir Kumericki http://www.phy.hr/~kkumer/
From: Bryan on
Terry Reedy wrote:
> Peter Otten wrote:
>
> > 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 **.
>
> > The following experiment shows that you only need to implement a keys() and
> > __getitem__() method.
>
> > $ cat kw.py
> > class A(object):
> >      def keys(self): return list("ab")
> >      def __getitem__(self, key):
> >          return 42
[...]
> > However, if you have A inherit from dict...
[...]
> > it stops working -- probably a side-effect of some optimization.
> > So if you change your hubDict's base class from dict to object you should
> > get the desired behaviour.
>
> In 2.6, the requirement changed from '(subclass of) dictionary' to
> 'mapping' so this is a bit strange. It sort of looks like a bug. I will
> test with 3.1 tomorrow (later today, actually).

I get the same bug-like behavior in 3.1. I think Peter is right that
it's probably a side-effect of an optimization. kkumer seems to have
completely over-ridden the methods of dict, but if we insert into his
hubDict with the parent class's method:

dict.__setitem__(dh, 'c', 3)

Then the **dh argument passes the keyword arg c=3.


--
--Bryan