索引时元组解包
Tuple unpacking while indexing
这个有效:
x = ['foo', 'bar']
y = [*x]
print(y) # prints ['foo', 'bar']
但这不是:
x = ['foo', 'bar']
y[*x] # raises SyntaxError (not NameError!)
如何在索引时解压元组?
这里有两个我想使用这种方法的示例,但我更想了解为什么 *
- 解包似乎在一般索引中不受支持。
import numpy as np
def lookup(a: np.ndarray, coordinates: tuple) -> float:
return a[*coordinates]
a1 = np.zeros((2, 2))
print(lookup(a1, (0, 1)) # Should print 0
a2 = np.zeros(2, 2, 2))
print(lookup(a2, (0, 0, 1)) # Should print 0
或
from typing import Tuple
NUM_DIMENSIONS = 2 # Might change at a later point in time
# Should be equivalent to Tuple[float ,float]
Result = Tuple[*([float] * NUM_DIMENSIONS)]
def get() -> Result:
...
参考你的例子:
import numpy as np
def lookup(a: np.ndarray, coordinates: tuple) -> float:
return a[*coordinates]
a1 = np.zeros((2, 2))
print(lookup(a1, (0, 1))
a2 = np.zeros(2, 2, 2))
print(lookup(a2, (0, 0, 1))
NumPy 已经接受像 a[coordinates]
这样的索引,其中 coordinates
是一个元组,不需要星号运算符:
>>> a = np.arange(8).reshape(2, 2, 2)
>>> a[(1, 1, 0)]
6
如果您使用列表进行索引,您会得到一种不同的有用行为:
>> a[[1, 1, 0], [0]]
array([[4, 5],
[4, 5],
[0, 1]])
Python的索引已经内置了对一般元组的支持(不仅仅是NumPy),所以这里不需要拆包。
一般来说,对于type(foo).__getitem__(foo, x)
,foo[x]
是syntactic sugar。让我们详细看看它是如何工作的:
class Foo:
def __getitem__(self, key):
print(repr(key))
foo = Foo()
如果我们用单个值索引到 foo
,那么它会原封不动地传递给 __getitem__
,无论它是标量、列表还是元组:
foo[0] # prints 0
foo[(0, 1)] # prints (0, 1)
foo[[0, 1]] # prints [0, 1]
有趣的情况是当我们在索引时直接提供多个值时会发生什么(没有将它们包装在元组或列表中):
foo[0, 1] # prints (0, 1)
所以多个值自动包装在一个元组中! foo
无法区分foo[0, 1]
和foo[(0, 1)]
。这是因为在 Python grammar 中,索引是一个表达式(或切片,但这里不适用)——而在表达式中,一个 ,
形成一个元组:
x = 1, 2
print(repr(x)) # prints (1, 2)
因此,索引中的参数解析与函数调用不同(逗号分隔参数而不是形成元组)。
所以,总的来说,在索引中不需要迭代器解包。只需将迭代器转换为元组,将其用作索引。
x = ['foo', 'bar']
y[*x] # raises SyntaxError (not NameError!)
这会引发语法错误,因为 * 和 x 被视为两个独立的事物,而不是一个。
例如:如果我执行以下操作
type(*x)
这个returns错误
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type() takes 1 or 3 arguments
这意味着 *x 不被视为一个单独的实体,而是两个独立的实体。
此外,
>>> x = ['foo', 'bar']
>>> print(*x)
foo bar
>>> print(x)
['foo', 'bar']
>>> y[*x]
File "<stdin>", line 1
y[*x]
^
SyntaxError: invalid syntax
>>> y[foo bar] #this is y[*x]
File "<stdin>", line 1
y[foo bar]
^
SyntaxError: invalid syntax
这个有效:
x = ['foo', 'bar']
y = [*x]
print(y) # prints ['foo', 'bar']
但这不是:
x = ['foo', 'bar']
y[*x] # raises SyntaxError (not NameError!)
如何在索引时解压元组?
这里有两个我想使用这种方法的示例,但我更想了解为什么 *
- 解包似乎在一般索引中不受支持。
import numpy as np
def lookup(a: np.ndarray, coordinates: tuple) -> float:
return a[*coordinates]
a1 = np.zeros((2, 2))
print(lookup(a1, (0, 1)) # Should print 0
a2 = np.zeros(2, 2, 2))
print(lookup(a2, (0, 0, 1)) # Should print 0
或
from typing import Tuple
NUM_DIMENSIONS = 2 # Might change at a later point in time
# Should be equivalent to Tuple[float ,float]
Result = Tuple[*([float] * NUM_DIMENSIONS)]
def get() -> Result:
...
参考你的例子:
import numpy as np
def lookup(a: np.ndarray, coordinates: tuple) -> float:
return a[*coordinates]
a1 = np.zeros((2, 2))
print(lookup(a1, (0, 1))
a2 = np.zeros(2, 2, 2))
print(lookup(a2, (0, 0, 1))
NumPy 已经接受像 a[coordinates]
这样的索引,其中 coordinates
是一个元组,不需要星号运算符:
>>> a = np.arange(8).reshape(2, 2, 2)
>>> a[(1, 1, 0)]
6
如果您使用列表进行索引,您会得到一种不同的有用行为:
>> a[[1, 1, 0], [0]]
array([[4, 5],
[4, 5],
[0, 1]])
Python的索引已经内置了对一般元组的支持(不仅仅是NumPy),所以这里不需要拆包。
一般来说,对于type(foo).__getitem__(foo, x)
,foo[x]
是syntactic sugar。让我们详细看看它是如何工作的:
class Foo:
def __getitem__(self, key):
print(repr(key))
foo = Foo()
如果我们用单个值索引到 foo
,那么它会原封不动地传递给 __getitem__
,无论它是标量、列表还是元组:
foo[0] # prints 0
foo[(0, 1)] # prints (0, 1)
foo[[0, 1]] # prints [0, 1]
有趣的情况是当我们在索引时直接提供多个值时会发生什么(没有将它们包装在元组或列表中):
foo[0, 1] # prints (0, 1)
所以多个值自动包装在一个元组中! foo
无法区分foo[0, 1]
和foo[(0, 1)]
。这是因为在 Python grammar 中,索引是一个表达式(或切片,但这里不适用)——而在表达式中,一个 ,
形成一个元组:
x = 1, 2
print(repr(x)) # prints (1, 2)
因此,索引中的参数解析与函数调用不同(逗号分隔参数而不是形成元组)。
所以,总的来说,在索引中不需要迭代器解包。只需将迭代器转换为元组,将其用作索引。
x = ['foo', 'bar']
y[*x] # raises SyntaxError (not NameError!)
这会引发语法错误,因为 * 和 x 被视为两个独立的事物,而不是一个。 例如:如果我执行以下操作
type(*x)
这个returns错误
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type() takes 1 or 3 arguments
这意味着 *x 不被视为一个单独的实体,而是两个独立的实体。
此外,
>>> x = ['foo', 'bar']
>>> print(*x)
foo bar
>>> print(x)
['foo', 'bar']
>>> y[*x]
File "<stdin>", line 1
y[*x]
^
SyntaxError: invalid syntax
>>> y[foo bar] #this is y[*x]
File "<stdin>", line 1
y[foo bar]
^
SyntaxError: invalid syntax