哪个 object 完全支持 python 中位置参数(或键控参数)的星号(或双星号)?任何标准?

Which object exactly support asterisk(or double asterick) for positional argument(or keyward argument) in python? Any criterion?

我已经使用 *** 将参数传递给 Python2 中的函数,没有问题,通常使用 listsetdictionary.

def func(a, b, c):
   pass

l = ['a', 'b', 'c']
func(*l)

d = {'a': 'a', 'b': 'b', 'c': 'c'}
func(**d)

然而,在Python3中,出现了新的objects,将list替换为或某物,例如,dict_keysdict_valuesrangemap 等等。

虽然我已将我的 Python2 代码迁移到 Python3,但我需要确定新的 object 是否可以支持 [=] 中以前的 object 的操作17=] 这样做如果没有,我应该使用 type-cast 将代码更改为原始类型,例如 list(dict_keys) 或其他内容。

d = {'a': 'a', 'b': 'b'}
print(list(d.keys())[0])    # type-case to use list-index

对于迭代我可以通过下面的方式弄清楚。

import collections
isinstance(dict_keys, collections.Iterable)
isinstance(dict_values, collections.Iterable)
isinstance(map, collections.Iterable)
isinstance(range, collections.Iterable)

新的object是否可迭代看起来很清楚,但是就像问题的标题一样,position/keyword argumentasterisk操作如何?

到目前为止,所有 object 都用支持 asterisk 操作替换了 list 作为我的测试,但我需要明确的标准而不是手动测试。

我尝试了几种方法,但没有共同的标准。

  1. 都是Iterableclass?
    • 不支持,Iterable generator不支持。
  2. 都是Iteratorclass?
    • 不支持,Iterator generator不支持。
  3. 都是Containerclass?
    • 不是mapclass不是Container
  4. 他们都有一个共同点superclass class?
    • 没有普通的superclass(用Class.mro()测试过)

我怎么知道 object 是否支持 asterisk(*, **) 操作 position/keyword argument?

The single asterisk form ( *args ) is used to pass a non-keyworded, variable- length argument list, and the double asterisk form is used to pass a keyworded, variable-length argument list

args and kwargs explainedalso this one

每个可迭代的 "supports" 星号表达式;甚至发电机和地图也可以。但是,"an object supports *" 是一个误导性术语,因为星号表示 "unpack my interable and pass each element in order to the parameteres of an interface"。因此,* 运算符支持迭代。

这可能就是您的问题所在:您使用 * 的可迭代对象必须具有与接口具有的参数一样多的元素。例如,请参见以下片段:

# a function that takes three args
def fun(a, b, c):
    return a, b, c

# a dict of some arbitrary vals:
d  = {'x':10, 'y':20, 'z':30}            # 3 elements
d2 = {'x':10, 'y':20, 'z':30, 't':0}     # 4 elements 

您可以通过d以多种方式获得乐趣:

fun(*d)             # valid
fun(*d.keys())      # valid
fun(*d.values())    # valid

但是,您不能将 d2 传递给 fun,因为它有更多的元素 fun 采用参数:

fun(*d2)    # invalid 

您还可以使用 stared 表达式将地图传递给 fun。但请记住,map 的结果必须有与 fun 接受的参数一样多的参数。

def sq(x):
    return x**2

sq_vals = map(sq, *d.values())

fun(*sq_vals)    # Result (100, 400, 900)

如果生成器生成的元素与您的函数接受的参数一样多,那么生成器也是如此:

def genx():
    for i in range(3):
        yield i

fun(*genx())    # Result: (0, 1, 2)

为了检查是否可以使用带星号的表达式将可迭代对象解压到函数的接口中,您需要检查可迭代对象的元素数量是否与函数接受参数的元素数量相同。

如果你想让你的函数对不同长度的参数安全,你可以,例如,尝试按以下方式重新定义你的函数:

# this version of fun takes min. 3 arguments:
fun2(a, b, c, *args):
    return a, b, c

fun2(*range(10))    # valid
fun(*range(10))     # TypeError