更改 *splat 和 **splatty-splat 运算符对我的对象所做的操作 [英] Change what the *splat and **splatty-splat operators do to my object

查看:66
本文介绍了更改 *splat 和 **splatty-splat 运算符对我的对象所做的操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

<预><代码>>>>[*事物]['a', 'b', 'c']>>>[x 在事物中的 x]['d', 'e', 'f']>>>{**事物}{'hello world': '我是土豆!!'}

注意:通过__iter__(for x in thing")的迭代从*splat解包返回不同的元素.

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

解决方案

* 迭代对象并将其元素用作参数.** 遍历对象的 keys 并使用 __getitem__(相当于括号表示法)来获取键值对.要自定义 *,只需使您的对象可迭代,而要自定义 **,使您的对象成为映射:

class MyIterable(object):def __iter__(self):返回迭代器([1, 2, 3])类 MyMapping(collections.Mapping):def __iter__(self):返回迭代器('123')def __getitem__(self, item):返回整数(项目)def __len__(self):返回 3

如果你想让 *** 做一些除了上面描述的事情,你不能.我没有该声明的文档参考(因为找到你可以做这个"的文档比你不能做这个"更容易),但我有一个来源引用.PyEval_EvalFrameEx 调用 ext_do_call使用 *** 参数实现函数调用.ext_do_call 包含以下代码:

 if (!PyDict_Check(kwdict)) {PyObject *d;d = PyDict_New();如果(d == NULL)转到 ext_call_fail;如果(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 通过...

How do you override the result of unpacking syntax *obj and **obj?

For example, can you somehow create an object thing which behaves like this:

>>> [*thing]
['a', 'b', 'c']
>>> [x for x in thing]
['d', 'e', 'f']
>>> {**thing}
{'hello world': 'I am a potato!!'}

Note: the iteration via __iter__ ("for x in thing") returns different elements from the *splat unpack.

I had a look inoperator.mul and operator.pow, but those functions only concern usages with two operands, like a*b and a**b, and seem unrelated to splat operations.

解决方案

* iterates over an object and uses its elements as arguments. ** iterates over an object's keys and uses __getitem__ (equivalent to bracket notation) to fetch key-value pairs. To customize *, simply make your object iterable, and to customize **, make your object a mapping:

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

If you want * and ** to do something besides what's described above, you can't. I don't have a documentation reference for that statement (since it's easier to find documentation for "you can do this" than "you can't do this"), but I have a source quote. The bytecode interpreter loop in PyEval_EvalFrameEx calls ext_do_call to implement function calls with * or ** arguments. ext_do_call contains the following code:

        if (!PyDict_Check(kwdict)) {
            PyObject *d;
            d = PyDict_New();
            if (d == NULL)
                goto ext_call_fail;
            if (PyDict_Update(d, kwdict) != 0) {

which, if the ** argument is not a dict, creates a dict and performs an ordinary update to initialize it from the keyword arguments (except that PyDict_Update won't accept a list of key-value pairs). Thus, you can't customize ** separately from implementing the mapping protocol.

Similarly, for * arguments, ext_do_call performs

        if (!PyTuple_Check(stararg)) {
            PyObject *t = NULL;
            t = PySequence_Tuple(stararg);

which is equivalent to tuple(args). Thus, you can't customize * separately from ordinary iteration.

It'd be horribly confusing if f(*thing) and f(*iter(thing)) did different things. In any case, * and ** are part of the function call syntax, not separate operators, so customizing them (if possible) would be the callable's job, not the argument's. I suppose there could be use cases for allowing the callable to customize them, perhaps to pass dict subclasses like defaultdict through...

这篇关于更改 *splat 和 **splatty-splat 运算符对我的对象所做的操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆