I would like to be able to unpack my own dictionary-like class.
class FauxDict:
def __getitem__(self, key):
return 99
def __iter__(self):
return range(0, 1)
def to_map(self):
return map(lambda x: True, range(0, 2))
def bar(**kwargs):
pass
dct = {"x":1, "y":2}
bar(**dct) # no error
dct = FauxDict()
bar(**dct) # error
dct = FauxDict()
bar(**dct.to_map()) # error
The errors are:
bar(**dct) # error
TypeError: bar() argument after ** must be a mapping, not FauxDict
bar(**dct.to_map()) # error
TypeError: bar() argument after ** must be a mapping, not map
Also, which python class(es) technically qualify as being mappings?
Implementing .keys()
and .__getitem__()
will be sufficient to allow an instance of your custom class to be expanded using **
.
The relevant parts of the cpython source are in ceval.c which uses _PyDict_MergeEx
, and thus dict_merge
from dictobject.c which states:
/* We accept for the argument either a concrete dictionary object, * or an abstract "mapping" object. For the former, we can do * things quite efficiently. For the latter, we only require that * PyMapping_Keys() and PyObject_GetItem() be supported. */
And indeed, implementing these two methods works as you would expect:
class MyMapping:
def __init__(self, d):
self._d = d
def __getitem__(self, k):
return self._d[k]
def keys(self):
return self._d.keys()
def foo(a, b):
print(f"a: {a}")
print(f"b: {b}")
mm = MyMapping({"a":"A", "b":"B"})
foo(**mm)
Output:
a: A b: B
Side note: your .keys()
implementation need only return an iterable (e.g. a list would be fine), not necessarily a dict_keys
object like I do above for simplicity. That line could also have been return list(self._d.keys())
without issue.
Something unusual like the following would also work:
class MyMapping:
def __getitem__(self, k):
return 2
def keys(self):
return ["a", "b", "c"]
def foo(a, b, **kwargs):
print(f"a: {a}")
print(f"b: {b}")
print(f"kwargs: {kwargs}")
mm = MyMapping()
foo(**mm)
Output:
a: 2 b: 2 kwargs: {'c': 2}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With