我创建了一个自定义类,我希望在实例上使用**
运算符将其传递给函数。我已经定义了__getitem__
和__iter__
,但是当我尝试f(**my_object)
时,我正在
`TypeError: argument must be a mapping, not 'MyClass'`
所需的最低方法是什么,以便自定义类符合映射条件?
答案 0 :(得分:5)
**
不是运算符,它是call syntax:
如果语法
**expression
出现在函数调用中,则表达式必须求值为mapping,其内容将被视为附加关键字参数。
因此,如果您的班级实施Mapping
methods,那么您应该好好去。您需要的不仅仅是__getitem__
和__iter__
。
Mapping
是Collection
,因此必须至少定义__getitem__
,__iter__
和__len__
;此外,大多数__contains__
,keys
,items
,values
,get
,__eq__
和__ne__
都是预料之中的。如果您的自定义类直接继承自collections.abc.Mapping
,则只需要实现前三个。
演示:
>>> from collections.abc import Mapping
>>> class DemoMapping(Mapping):
... def __init__(self, a=None, b=None, c=None):
... self.a, self.b, self.c = a, b, c
... def __len__(self): return 3
... def __getitem__(self, name): return vars(self)[name]
... def __iter__(self): return iter('abc')
...
>>> def foo(a, b, c):
... print(a, b, c)
...
>>> foo(**DemoMapping(42, 'spam', 'eggs'))
42 spam eggs
如果在调试器下运行它,您将看到Python调用.keys()
方法,该方法返回一个字典视图,然后在视图时委托给自定义类__iter__
方法迭代。然后使用一系列__getitem__
调用检索这些值。因此,对于您的具体情况,缺少的是.keys()
方法。
另外,请注意Python可能会强制键是字符串!
>>> class Numeric(Mapping):
... def __getitem__(self, name): return {1: 42, 7: 'spam', 11: 'eggs'}[name]
... def __len__(self): return 3
... def __iter__(self): return iter((1, 7, 11))
...
>>> dict(Numeric())
{1: 42, 7: 'spam', 11: 'eggs'}
>>> def foo(**kwargs): print(kwargs)
...
>>> foo(**Numeric())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() keywords must be strings
答案 1 :(得分:1)
第一组方法用于模拟映射......
还建议映射提供方法
keys()
,values()
,items()
,get()
,clear()
,setdefault()
,{{ 1}},pop()
,popitem()
和copy()
的行为与Python标准字典对象的行为类似。建议[...]映射实现
update()
方法以允许有效使用in运算符......进一步建议[...]映射实现
__contains__()
方法以允许通过容器进行有效迭代