充当**解包映射的类

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...

问题描述:

如果不将 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__,,,,,,和keysitems`valuesgeteq`__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)
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   4046  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   2770  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Freshdesk、ClickUp、nTask、Hubstaff、Plutio、Productive、Targa、Bonsai、Wrike。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在项目管理过程中面临着诸多痛点,如任务分配不...
项目管理系统   90  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Monday、TeamGantt、Filestage、Chanty、Visor、Smartsheet、Productive、Quire、Planview。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多项目经理和团队在管理复杂项目时,常...
开源项目管理工具   105  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Smartsheet、GanttPRO、Backlog、Visor、ResourceGuru、Productive、Xebrio、Hive、Quire。在当今快节奏的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在选择项目管理工具时常常面临困惑:...
项目管理系统   93  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用