Python 区分作为一维索引传递给_getitem_uuu的元组与多维索引集?
考虑一个类来镜像传递给Python 区分作为一维索引传递给_getitem_uuu的元组与多维索引集?,python,indexing,tuples,magic-methods,Python,Indexing,Tuples,Magic Methods,考虑一个类来镜像传递给\uu getitem\uu的参数: class RequestedItems(object): def __getitem__(self, args): return args 一些示例(其中r=RequestedItems()): 我如何区分用户仅传递一个试图获取的项目时的情况,以及该项目本身是一个元组,与用户试图获取多维项目时的情况: In [83]: r[1, 2, 3] Out[83]: (1, 2, 3) In [84]: r[(1,
\uu getitem\uu
的参数:
class RequestedItems(object):
def __getitem__(self, args):
return args
一些示例(其中r=RequestedItems()
):
我如何区分用户仅传递一个试图获取的项目时的情况,以及该项目本身是一个元组
,与用户试图获取多维项目时的情况:
In [83]: r[1, 2, 3]
Out[83]: (1, 2, 3)
In [84]: r[(1, 2, 3)]
Out[84]: (1, 2, 3)
示例
作为一个可能需要的例子,考虑编写一个装饰器,它将使用任何传递给
def target_getitem(function_name):
def decorator(klass):
def __getitem__(self, args):
args = args if isinstance(args, tuple) else (args,) # For 1-D indexing
return getattr(self, function_name)(*args)
klass.__getitem__ = __getitem__
return klass
return decorator
然后我们可以这样做:
@target_getitem('sum')
class Foo(object):
def sum(self, *args):
import operator
return reduce(lambda x,y: operator.add(x,y), args)
那么这就行了:
f = Foo()
f[1, 2, 3] # <-- prints 6
f[1] #<-- prints 1
f[(1, 2, 3), (4, 5, 6)] # <-- prints (1, 2, 3, 4, 5, 6)
f=Foo()
f[1,2,3]#注意,如果用户知道这个问题,用户可以使用尾随逗号调用f[(1,2,3),]
,强制将元组视为多维切片的第一维度。但是,这需要用户首先知道这一点,然后在其他单值get请求(例如f['foo']
)不需要相同的约定时放置尾随逗号(这是非常有趣的,因为'foo'
的行为应该像一个字符元组,但是\uuuu getitem\uuuuuuu
并不假设您想要('f','o','o')
。难道没有办法区分这些情况吗。信息是单个元组还是“多个参数”传递的已在解析器中丢失。subscription
的语法不接受多个参数,而是接受一个expression\u list
。赋值也使用该语法,因此也无法区分a=1,2
和a=(1,2)
。在a=1,2
vsa=(1,2)
的情况下,这是有意义的。在有效的Python中,对a=1,2
没有任何解释会允许a
与(1,2)不同
。但是在我上面用\uuu getitem\uuuu>给出的例子中,在解析器中称之为bug几乎就足够了,因为有多种有效的方法来解释f[(1,2,3)]
的含义。值得注意的是,因为f['foo']
的解析方式与f[('f','o','o')的解析方式不同
那么,不管解决方案是什么,Python当前的行为似乎无法辩护,因为tuple
s的字符和int
s的tuple
s之间不一致。FWIW我同意这是一个解析器(或者可能是语言定义)错误。调用类似func(1,2,3)的函数
应该与使用func((1,2,3))调用它有所区别
而不需要在后者的末尾添加逗号(这是唯一想到的解决方法).@prpl.mnky.dshwshr我并不是试图通过解释当前行为在解析器中的实现方式来为其辩护,而是试图解释为什么我认为在实现\uu getitem\uuuuuuu()时,目前无法区分这些情况
.IMHO,如果今天设计的话,我会投票支持下标操作符像函数调用一样解析参数,并将这些参数作为单个参数传递给\uuuu getitem\uuuu()
。也就是说,foo[1,2]将等同于foo.\uu getitem\uuuuu(1,2)。但遗憾的是,事实并非如此。
f = Foo()
f[1, 2, 3] # <-- prints 6
f[1] #<-- prints 1
f[(1, 2, 3), (4, 5, 6)] # <-- prints (1, 2, 3, 4, 5, 6)
f[(1, 2, 3)] # <-- prints 6, but should print '(1, 2, 3)'