如何为我自己的用户定义类覆盖可变参数函数中用于 kwargs 的 `**` 运算符?

Sam*_*oon 5 python variadic-functions python-3.x

我希望能够解压我自己的类似字典的类。

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
Run Code Online (Sandbox Code Playgroud)

错误是:

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
Run Code Online (Sandbox Code Playgroud)

另外,哪个python类在技术上有资格作为映射?

jed*_*rds 5

实施.keys().__getitem__()将足以允许使用 扩展自定义类的实例**

cpython 源代码的相关部分位于ceval.c中,它使用_PyDict_MergeEx, 因此dict_merge来自dictobject.c,其中指出:

    /* 我们接受一个具体的字典对象作为参数,
     * 或抽象的“映射”对象。对于前者,我们可以做
     * 事情非常有效。对于后者,我们只需要
     * 支持 PyMapping_Keys() 和 PyObject_GetItem()。
     */

事实上,实现这两种方法的效果正如您所期望的:

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)
Run Code Online (Sandbox Code Playgroud)

输出:

一个:一个
乙:乙

旁注:您的.keys()实现只需要返回一个可迭代对象(例如列表就可以了),不一定是dict_keys像我上面为简单起见所做的那样的对象。这条线也可能没有return list(self._d.keys())问题。

像下面这样的不寻常的东西也可以工作:

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)
Run Code Online (Sandbox Code Playgroud)

输出:

a2
乙:2
夸格斯:{'c':2}