Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sqlite/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 更改*splat和**splatty splat操作符对我的对象所做的操作_Python_Iterable Unpacking_Splat_Double Splat - Fatal编程技术网

Python 更改*splat和**splatty splat操作符对我的对象所做的操作

Python 更改*splat和**splatty splat操作符对我的对象所做的操作,python,iterable-unpacking,splat,double-splat,Python,Iterable Unpacking,Splat,Double Splat,如何覆盖解包语法的结果*obj和**obj 例如,您能否以某种方式创建一个对象thing,其行为如下: >>> [*thing] ['a', 'b', 'c'] >>> [x for x in thing] ['d', 'e', 'f'] >>> {**thing} {'hello world': 'I am a potato!!'} 注意:通过\uuuu iter\uuuu(“for x in thing”)的迭代从*splat解包返回不

如何覆盖解包语法的结果
*obj
**obj

例如,您能否以某种方式创建一个对象
thing
,其行为如下:

>>> [*thing]
['a', 'b', 'c']
>>> [x for x in thing]
['d', 'e', 'f']
>>> {**thing}
{'hello world': 'I am a potato!!'}
注意:通过
\uuuu iter\uuuu
(“for x in thing”)的迭代从*splat解包返回不同的元素


我查看了
operator.mul
operator.pow
,但这些函数只涉及两个操作数的用法,如
a*b
a**b
,似乎与splat操作无关

*
迭代对象并将其元素用作参数
**
迭代对象的
,并使用
\uuu getitem\uuu
(相当于括号表示法)获取键值对。要自定义
*
,只需将对象设置为可编辑,要自定义
***
,请将对象设置为映射:

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
如果您想让
*
***
做除上述内容之外的事情,您不能。我没有这句话的文档参考(因为“你能做到”比“你不能做到”更容易找到文档),但我有一个源引用。字节码解释器在调用中循环,以实现带有
*
**
参数的函数调用
ext\u do\u call
包含以下代码:

        if (!PyDict_Check(kwdict)) {
            PyObject *d;
            d = PyDict_New();
            if (d == NULL)
                goto ext_call_fail;
            if (PyDict_Update(d, kwdict) != 0) {
如果
**
参数不是dict,则会创建dict并执行普通的
更新
以从关键字参数初始化它(除了
PyDict\u update
不接受键值对列表)。因此,您不能在实现映射协议的同时单独定制
**

类似地,对于
*
参数,
ext\u do\u call
执行

        if (!PyTuple_Check(stararg)) {
            PyObject *t = NULL;
            t = PySequence_Tuple(stararg);
这相当于
元组(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']

迭代器协议由从
\uuuu iter\uuuu
返回的生成器对象满足(请注意,
Thing()
实例本身不是迭代器,尽管它是可迭代的)。映射协议通过存在
键()
\uuuu getitem\uuuu
来满足。然而,如果它还不明显,你不能连续两次调用
*东西
,然后让它连续两次解包
a、b、c
,这样它就不会像假装的那样覆盖splat了。

我99%确定你不能。。。但是如果在这里被证明是错误的,您应该能够实现iterable或映射协议。但是,我在使映射正常工作时遇到了奇怪的问题。@wim:那么不是。这会让人非常困惑。@wim:它们不是单独的运算符。它们是函数调用语法的一部分。您不能单独自定义它们,原因与您不能自定义当某些内容作为常规参数传递时发生的情况相同。@wim:文档只说“这是
*
**
要做的”,而不是“您不能让他们做其他事情”。我想我会找出源代码的哪个部分实现了相关的操作码。我看到了两个新的神奇方法的PEP:
\uuuuuSplat\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
,在正常情况下,默认返回到
\uuuuuuuuuuuuuuuuuuuuuu
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
-with-
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu getitem
。@mapf:从技术上讲,它只在当前的cpyt“如果函数调用中出现语法
**expression
expression
必须计算为映射,其内容被视为附加关键字参数。”。“实现足够让
**
获取您的对象会导致错误和混乱,因此我故意将其从我的答案中排除。让
*东西和
**东西
非常容易,至少总是按照您喜欢的方式操作,而不依赖于顺序——只需定义
定义键(self):return('hello world',)
您没有返回
\uuu len\uuu
是否有任何特殊原因?另外,如果您没有继承
映射
,那么您需要扩展
映射
?@madpysicator。在
Thing
的上下文中,这意味着我们必须定义
方法。如果您继承了
映射
,则需要定义抽象方法
\uuuu len\uuuu
,但我不在乎它在这里返回什么-只要名称解析即可。@wim。我一直认为只要
\uuu len\uuu
返回1就可以了。有趣。