当我写**object_identifier时,有没有一个被调用的神奇方法?

6 浏览
0 Comments

当我写**object_identifier时,有没有一个被调用的神奇方法?

如果不使用字典的子类化,要将一个类视为映射并将其传递给带有**的方法,需要满足什么条件?\n

from abc import ABCMeta
class uobj:
    __metaclass__ = ABCMeta
uobj.register(dict)
def f(**k): return k
o = uobj()
f(**o)
# 输出:f()参数后的**必须是映射,而不是uobj

\n至少要能抛出映射功能缺失的错误,这样我才能开始实现。\n我已经查看了模拟容器类型的方法,但仅定义魔术方法没有效果,并且使用ABCMeta来覆盖并将其注册为字典时,验证断言作为子类是有效的,但是isinstance(o, dict)则失败。理想情况下,我甚至不想使用ABCMeta

0
0 Comments

有没有一个魔法方法在我写**object_identifier时被调用?

这个问题的出现原因是,当我们试图使用一个非映射对象与**一起使用时,会出现以下错误:

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()。

这是否意味着只有getitem和keys需要为ti定义?

是的,这正是这个注释所暗示的。这个发现也在最佳答案中得到了反映。我发表了这个答案,以展示如何找到这样的东西。

0
0 Comments

问题的原因是,当我们写下一个对象的标识符时,是否有一个魔法方法会被调用?解决方法是,如果我们想创建一个映射(不仅仅是满足传递给函数的要求),我们应该继承自`collections.abc.Mapping`。根据文档的描述,我们只需要实现以下方法:`__getitem__`、`__len__`和`__iter__`。Mixin将为我们实现其他所有方法:`__contains__`、`keys`、`items`、`values`、`get`、`__eq__`和`__ne__`。该方法已经移至`collections.abc`包中。

如果我们想创建一个映射对象,并且希望在写入对象标识符时自动调用某个方法,我们应该继承自`collections.abc.Mapping`并实现`__getitem__`、`__len__`和`__iter__`方法。这样,我们就可以利用Mixin自动实现其他相关方法。

0
0 Comments

在上面的代码中,通过定义类D并实现了keys()和__getitem__()方法来解决了问题。当调用f()函数时,传入的参数是D()对象,这里使用了**kwds的形式进行参数传递,**表示将D()对象的keys()方法返回的键作为参数传递给f()函数。在f()函数中,通过print语句输出了传入的参数,即{'a': 'A', 'b': 'B'}。

在这个例子中,我们可以看到当使用**object_identifier的形式进行参数传递时,会调用对象的keys()方法来获取键,并且调用对象的__getitem__()方法来获取对应键的值。这是因为在Python中,**object_identifier会将对象的keys()方法返回的键作为参数传递给函数,并且将调用对象的__getitem__()方法来获取对应键的值。

因此,如果想要在使用**object_identifier时自定义键和值的获取方式,可以通过在对象中实现keys()和__getitem__()方法来实现。

以上就是针对问题的解决方法和出现的原因的整理。通过定义类并实现特定的方法,我们可以在使用**object_identifier时自定义键和值的获取方式。

0