【问题标题】:Is there a difference between `board[x, y]` and `board[x][y]` in Python?Python 中的 `board[x, y]` 和 `board[x][y]` 有区别吗?
【发布时间】:2019-12-12 13:12:39
【问题描述】:

我正在处理 tutorial on GeekforGeeks website 并注意到他们正在使用 board[x,y] 检查数组中的一个点,这是我以前从未见过的。我认为这行不通,但是当我运行程序时,一切都按预期进行。

我尝试使用他们上面概述的方法与我更熟悉的方法 (board[x][y]) 运行一个较小的代码示例,但是当我运行我的代码时,我得到 TypeError: list indices must be integers or slices, not tuple

我的代码:

board = [[1,1,1], [1,2,2], [1,2,2]]
win = 'True'

if board[1][1] == 2:
    win = 'True by normal standards'
    print(win)
if board[1, 1] == 2:
    win = 'True by weird standards'
    print(win)

print(win)

他们的代码:

def row_win(board, player): 
    for x in range(len(board)): 
        win = True

        for y in range(len(board)): 
            if board[x, y] != player: 
                win = False
                continue

        if win == True: 
            return(win) 
    return(win) 

有人可以向我解释为什么board[x,y] 有效吗?到底发生了什么?除了创建列表之外,我以前从未见过这种情况,并且在概念上没有掌握它。

【问题讨论】:

  • 如果您在交互模式下运行(python -i),那么type(board) 将显示board 是什么类型(numpy.ndarraypandas.DataFrame)。或者查看创建和初始化board 的行。

标签: python arrays list numpy indexing


【解决方案1】:

他们能够做到这一点,因为他们使用的是 NumPy,这不会引发错误。

>>> a = np.array([[1,1,1], [1,2,2], [1,2,2]])
>>> a[1,1]
2
>>> # equivalent to
>>> a = [[1,1,1], [1,2,2], [1,2,2]]
>>> a[1][1]
2
>>> 

【讨论】:

  • 在 numpy 中也一样吗?还是两者中的一个(显着)性能更高或以任何其他方式更可取?
  • @lucidbrot: a[1,1]numpy 中会更高效,因为它避免创建额外的numpy 数组包装器; a[1][1] 必须加载 a,索引到 1,为该行创建一个包装器,然后在该行上索引到 1 以获取单元格的值,然后清理包装器。 a[1,1] 直接加载单元格的值而不创建额外的包装对象(如果索引不是恒定的,它确实必须根据需要创建一个 tuple,但小的 tuple 文字在 Python 中经过专门优化,因此成本相当小)。
【解决方案2】:

之所以有效,是因为他们使用的对象(在本例中为 numpy 数组)重载了 __getitem__ 方法。看这个玩具例子:

class MyArray:
  def __init__(self, arr):
    self.arr = arr
  def __getitem__(self, t):
    return self.arr[t[0]][t[1]]

myarr = MyArray([[1,1,1], [1,2,2], [1,2,2]])
print(myarr[0,1])

【讨论】:

    【解决方案3】:

    它实际上不适用于基础 Python(如您的示例)。如果你运行你的代码,Python 会抛出一个异常:'TypeError: list indices must be integers or slices, not tuple'。

    传递给board1, 1 被解释为一个元组,因为板应该用整数或切片索引,所以这不起作用。

    但是,如果board 是某种类型的类似数组的数据结构,并且开发人员已经实现了对元组索引的支持,那么这将起作用。这方面的一个例子是numpy 中的数组。

    【讨论】:

    • 不要说 “它实际上不起作用。” 你的意思是 “它实际上不起作用 在基础 Python 中,如果board 是一个列表列表
    • 鉴于正在讨论的示例,我觉得这是隐含的,但我已经更新了答案。
    • Grismar OP 显然不知道 numpy/pandas,也没有习惯使用type(board) 来实际查看它是什么类型的对象。您可能会认为这都是针对高级用户的,但它肯定不适用于新用户。
    • 即使更新后的答案也错误地暗示如果没有第三方库,这将无法工作,而它显然可以:像x = {}; x[1, 1] = 42 这样微不足道的代码可以按预期工作。或者,更重要的是,没有什么能阻止人们用很少的代码在基础 Python 中实现二维数组类。
    • @Konrad Rudolph - 你给出的例子是一个用元组索引的字典。这不仅是一种可怕的反模式,而且显然也不是 OP 所要求的。我同意 smci 所说的一点——可能不清楚我的意思是基础 python;许多库实际上实现了具有多维索引的数组。但是,您提供的示例表明,这样做并非微不足道,当然也不是基础 Python。最后,如果用元组索引的 dict 最好地实现所需的解决方案,那完全符合我的回答。
    【解决方案4】:

    board[x, y] 语法可能被应用于 numpy 数组,它接受此语法以实现行/列索引切片操作。看看这些例子:

    >>> x = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])  # creates 2D array
    >>> x
    array([[1, 2, 3],
           [4, 5, 6],
           [7, 8, 9]])
    
    >>> x[1]  # get second row (remember, index starts at 0)
    array([4, 5, 6])
    
    >>> x[:, 2]  # get third column
    array([3, 6, 9])
    
    >>> x[1, 2]  # get element on second row, third column
    6
    
    >>> x[1][2]  # same as before but with non-broadcasting syntax (i.e. works for lists as you are used to)
    6
    
    >>> x[1, 0:2]  # get first two elements of second row  
    array([4, 5])
    
    >>> x[0:2, 0:2]  # subsets the original array, "extracting" values from the first two columns/rows only
    array([[1, 2],
           [4, 5]])
    

    当然,写my_list[x, y] 会引发错误,因为x, y 实际上是一个元组(x, y),而常规列表不能将元组作为索引值。

    【讨论】:

    • 谢谢!我是 NumPy 的新手,所以这非常有用
    【解决方案5】:

    因为他们的 board 要么是 numpy.ndarray 要么是某种包装它的类型,例如pandas.DataFrame board[x,y] 是 pandas 2D 索引,而不是基础 Python。

    你应该完成type(board)。或者向我们展示创建和初始化 board 的行。

    另外,当你说“当我运行程序时,一切都按预期进行”时,你应该在交互模式下运行 (python -i),然后你可以运行类似 type(board) 的查询(或在 iPython/jupyter 中键入 @ 987654329@查看变量列表及其类型)

    【讨论】:

      【解决方案6】:

      在python中,[]__getitem__,可以很容易地改写。

      而且,python 中的1, 2 会给我们一个元组。是的,我们真的不需要() 来创建一个非空元组。

      所以,Numpy 可以很容易地做到这一点,即使我也可以。

      In [1]: 1, 1
      Out[1]: (1, 1)
      
      In [2]: type(_)
      Out[2]: tuple
      
      In [3]: a = {(1, 1): 3}
      
      In [4]: a[1, 1]
      Out[4]: 3
      
      In [5]: a[(1, 1)]
      Out[5]: 3
      
      In [6]: class NumpyArray(list):
         ...:     def __getitem__(self, index):
         ...:         if isinstance(index, tuple) and len(index) == 2:
         ...:             return self[index[0]][index[1]]
         ...:         return super().__getitem__(index)
         ...:
      
      In [7]: b = NumpyArray([[0, 1], [2, 3]])
      
      In [8]: b[1, 1]
      Out[8]: 3
      

      您可以使用下面的代码来尝试自己的 iPython。

      class NumpyArray(list):
          def __getitem__(self, index):
              if isinstance(index, tuple) and len(index) == 2:
                  return self[index[0]][index[1]]
              return super().__getitem__(index)
      
      b = NumpyArray([[0, 1], [2, 3]])
      b[1, 1]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-16
        • 1970-01-01
        相关资源
        最近更新 更多