如何为我自己的用户定义 类 覆盖可变参数函数中用于 kwargs 的 `**` 运算符?
How do I override the `**` operator used for kwargs in variadic function for my own user-defined classes?
我希望能够解压我自己的字典式 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
错误是:
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
此外,哪个 python class(es) 在技术上符合映射?
实施 .keys()
和 .__getitem__()
将足以允许使用 **
.
扩展自定义 class 的实例
cpython 源代码的相关部分在 ceval.c which uses _PyDict_MergeEx
, and thus dict_merge
from dictobject.c 中,其中指出:
/* 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.
*/
事实上,实现这两种方法的效果与您预期的一样:
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)
输出:
a: A
b: B
旁注:您的 .keys()
实现只需要 return 一个可迭代对象(例如,一个列表就可以),不一定是像我上面为简单起见所做的 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)
输出:
a: 2
b: 2
kwargs: {'c': 2}
我希望能够解压我自己的字典式 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
错误是:
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
此外,哪个 python class(es) 在技术上符合映射?
实施 .keys()
和 .__getitem__()
将足以允许使用 **
.
cpython 源代码的相关部分在 ceval.c which uses _PyDict_MergeEx
, and thus dict_merge
from dictobject.c 中,其中指出:
/* 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. */
事实上,实现这两种方法的效果与您预期的一样:
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)
输出:
a: A b: B
旁注:您的 .keys()
实现只需要 return 一个可迭代对象(例如,一个列表就可以),不一定是像我上面为简单起见所做的 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)
输出:
a: 2 b: 2 kwargs: {'c': 2}