你如何重写拆包语法的结果*obj
和**obj
?
例如,你能以某种方式创建一个对象thing
,其行为是这样的:
>>> [*thing]
['a', 'b', 'c']
>>> [x for x in thing]
['d', 'e', 'f']
>>> {**thing}
{'hello world': 'I am a potato!!'}
注意:通过迭代__iter__
(“关于x的事”)返回从*图示解压不同的元素。
我在看operator.mul
和operator.pow
,但这些功能只关心用途有两个操作数,像a*b
和a**b
,而且似乎无关的图示操作。
*
在一个对象上进行迭代,并且使用其元素作为参数。 **
在对象的迭代keys
,并使用__getitem__
(相当于括号符号)来抓取键-值对。 要定制*
和**
,只是让你的对象可迭代或映射:
class MyIterable(object):
def __iter__(self):
return iter([1, 2, 3])
class MyMapping(collections.Mapping):
def __iter__(self):
return iter('123')
def __getitem__(self, item):
return int(item)
def __len__(self):
return 3
如果你想*
与**
做除了什么如上所述,你不能什么。 我没有该语句一个文件引用(因为它更容易找到文档“你可以做到这一点”比“你不能这样做”),但我有一个源报价。 在字节码解释器循环PyEval_EvalFrameEx
呼吁ext_do_call
实现函数调用*
或**
参数。 ext_do_call
包含以下代码:
if (!PyDict_Check(kwdict)) {
PyObject *d;
d = PyDict_New();
if (d == NULL)
goto ext_call_fail;
if (PyDict_Update(d, kwdict) != 0) {
其中,如果**
参数不是一个字典,生成一个字典,并执行通常的update
从关键字参数(除了初始化它PyDict_Update
将不接受键-值对的列表)。 因此,不能自定义**
分别从执行所述映射协议。
同样,对于*
参数, ext_do_call
执行
if (!PyTuple_Check(stararg)) {
PyObject *t = NULL;
t = PySequence_Tuple(stararg);
其等同于tuple(args)
。 因此,你不能自定义*
分别从普通迭代。
这将会是可怕的混乱,如果f(*thing)
和f(*iter(thing))
做不同的事情。 在任何情况下, *
和**
是函数调用的语法,而不是独立的运营商的一部分,所以他们定制(如果可能)将是可调用的工作,而不是争论的。 我想有可能是用例允许调用自定义它们,或许通过dict
子像defaultdict
通过...
我没有在作出该行为我我的问题是如何描述的目标成功,但我真的有作弊。 因此,只要张贴这在这里的乐趣,真的 -
class Thing:
def __init__(self):
self.mode = 'abc'
def __iter__(self):
if self.mode == 'abc':
yield 'a'
yield 'b'
yield 'c'
self.mode = 'def'
else:
yield 'd'
yield 'e'
yield 'f'
self.mode = 'abc'
def __getitem__(self, item):
return 'I am a potato!!'
def keys(self):
return ['hello world']
迭代器协议是由返回一个生成器对象满足__iter__
(注意, Thing()
实例本身不是一个迭代器 ,虽然它是可迭代 )。 所述映射协议被存在满足keys()
和__getitem__
。 然而,如果它是不是已经很明显,你不能叫*thing
连续两次并将其解压a,b,c
连续两次-所以它不是一个真正覆盖图示喜欢假装做。