充当**解包映射的类
- 2025-03-10 08:52:00
- admin 原创
- 68
问题描述:
如果不将 dict 子类化,那么类将需要被视为映射,以便可以将其传递给方法**
。
from abc import ABCMeta
class uobj:
__metaclass__ = ABCMeta
uobj.register(dict)
def f(**k): return k
o = uobj()
f(**o)
# outputs: f() argument after ** must be a mapping, not uobj
至少到了它抛出缺少映射功能的错误的时候,我就可以开始实施了。
我查看了模拟容器类型,但仅仅定义魔术方法没有任何效果,并且使用ABCMeta
它来覆盖并将其注册为字典会将断言验证为子类,但会失败isinstance(o, dict)
。理想情况下,我甚至不想使用ABCMeta
。
解决方案 1:
和__getitem__()
方法keys()
就足够了:
>>> class D:
def keys(self):
return ['a', 'b']
def __getitem__(self, key):
return key.upper()
>>> def f(**kwds):
print kwds
>>> f(**D())
{'a': 'A', 'b': 'B'}
解决方案 2:
如果你尝试创建一个 Mapping — 而不只是满足传递给函数的要求 — 那么你真的应该从 继承。如文档collections.abc.Mapping
中所述,你只需要实现:
__getitem__
__len__
__iter__
Mixin 将为您 实现其余一切:__contains__
,,,,,,和keys
。items
`valuesget
eq`__ne__
解决方案 3:
深入挖掘源头就能找到答案。
当尝试使用非映射对象时**
,会出现以下错误:
TypeError: 'Foo' object is not a mapping
如果我们在 CPython 源代码中搜索该错误,我们可以找到导致引发该错误的代码:
case TARGET(DICT_UPDATE): {
PyObject *update = POP();
PyObject *dict = PEEK(oparg);
if (PyDict_Update(dict, update) < 0) {
if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) {
_PyErr_Format(tstate, PyExc_TypeError,
"'%.200s' object is not a mapping",
Py_TYPE(update)->tp_name);
PyDict_Update
实际上是dict_merge
`dict_merge,当返回负数时会抛出错误。如果我们检查 的源代码
dict_merge`,我们可以看到导致返回 -1 的原因:
/* 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.
*/
if (a == NULL || !PyDict_Check(a) || b == NULL) {
PyErr_BadInternalCall();
return -1;
关键部分是:
对于后者,我们只要求支持 PyMapping_Keys() 和 PyObject_GetItem()。
解决方案 4:
使用数据类
更清洁,最终在质量方面表现更好,数据类的使用也有助于将正确的对象返回给keys
方法。
from dataclasses import dataclass
@dataclass(frozen=True)
class Person:
name: str
surname: str
age: int
def __getitem__(self, key):
return getattr(self, key)
def keys(self):
return self.__annotations__.keys()
josh_doe: Person = Person("John", "Doe", 31)
print(f"John object : {josh_doe}")
user_data = {**josh_doe}
print(user_data)
相关推荐
热门文章
项目管理软件有哪些?
热门标签
曾咪二维码
扫码咨询,免费领取项目管理大礼包!
云禅道AD