更改什么*图示和** splatty-图示运营商做我的对象更改什么*图示和** splatty-图示

2019-05-12 03:04发布

你如何重写拆包语法的结果*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.muloperator.pow ,但这些功能只关心用途有两个操作数,像a*ba**b ,而且似乎无关的图示操作。

Answer 1:

*在一个对象上进行迭代,并且使用其元素作为参数。 **在对象的迭代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通过...



Answer 2:

我没有在作出该行为我我的问题是如何描述的目标成功,但我真的有作弊。 因此,只要张贴这在这里的乐趣,真的 -

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连续两次-所以它不是一个真正覆盖图示喜欢假装做。



文章来源: Change what the *splat and **splatty-splat operators do to my object