Is there a difference between `board[x, y]` and `board[x][y]` in Python?
Question:
I’m working through a tutorial on GeekforGeeks website and noticed that they are checking a point in an array using board[x,y]
, which I’ve never seen before. I don’t think this would work, but when I run the program, everything goes as expected.
I tried running a smaller code example using their method outlined above vs the method I’m more familiar with (board[x][y]
), but when I run my code, I get TypeError: list indices must be integers or slices, not tuple
My code:
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)
Their code:
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)
Can someone explain to me why board[x,y]
works, and what exactly is happening? I’ve never seen this before except to create lists, and am not grasping it conceptually.
Answers:
They’re able to do that since they’re using NumPy, which won’t throw an error on that.
>>> 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
>>>
It does not actually work in base Python (like your example). If you run your code, Python throws an exception: ‘TypeError: list indices must be integers or slices, not tuple’.
The 1, 1
passed to board
is interpreted as a tuple and since board should be indexed with integers or slices, this won’t work.
However, if board
were some type of array-like data structure and the developer had implemented support for indexing with tuples, this would work. An example of this is arrays in numpy
.
The board[x, y]
syntax is probably being applied onto a numpy array, which accepts this syntax in order to implement row/column indexed slicing operations. Take a look at these examples:
>>> 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]])
Of course, writing my_list[x, y]
throws an error because x, y
is actually a tuple (x, y)
, and regular lists can’t work with tuples as an indexing value.
Because their board
is either numpy.ndarray
or some type that wraps it, e.g. pandas.DataFrame
board[x,y]
is pandas 2D indexing, not base Python.
You should have done type(board)
. Or show us the lines that create and initialize board
.
Also, when you say “when I run the program, everything goes as expected”, you should run in interactive mode (python -i
), then you could run queries like type(board)
(or in iPython/jupyter type whos
to see alist of variables and their types)
That works because the object they are using (in this case numpy array) overloads the __getitem__
method. See this toy example:
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])
In python, []
is __getitem__
, which can be easily rewritten.
And, 1, 2
in python will give us a tuple. yes, we don’t really need ()
to create a non empty tuple.
So, Numpy can do this very easily, even I can.
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
You can use below code to try on your own 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]
I’m working through a tutorial on GeekforGeeks website and noticed that they are checking a point in an array using board[x,y]
, which I’ve never seen before. I don’t think this would work, but when I run the program, everything goes as expected.
I tried running a smaller code example using their method outlined above vs the method I’m more familiar with (board[x][y]
), but when I run my code, I get TypeError: list indices must be integers or slices, not tuple
My code:
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)
Their code:
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)
Can someone explain to me why board[x,y]
works, and what exactly is happening? I’ve never seen this before except to create lists, and am not grasping it conceptually.
They’re able to do that since they’re using NumPy, which won’t throw an error on that.
>>> 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
>>>
It does not actually work in base Python (like your example). If you run your code, Python throws an exception: ‘TypeError: list indices must be integers or slices, not tuple’.
The 1, 1
passed to board
is interpreted as a tuple and since board should be indexed with integers or slices, this won’t work.
However, if board
were some type of array-like data structure and the developer had implemented support for indexing with tuples, this would work. An example of this is arrays in numpy
.
The board[x, y]
syntax is probably being applied onto a numpy array, which accepts this syntax in order to implement row/column indexed slicing operations. Take a look at these examples:
>>> 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]])
Of course, writing my_list[x, y]
throws an error because x, y
is actually a tuple (x, y)
, and regular lists can’t work with tuples as an indexing value.
Because their board
is either numpy.ndarray
or some type that wraps it, e.g. pandas.DataFrame
board[x,y]
is pandas 2D indexing, not base Python.
You should have done type(board)
. Or show us the lines that create and initialize board
.
Also, when you say “when I run the program, everything goes as expected”, you should run in interactive mode (python -i
), then you could run queries like type(board)
(or in iPython/jupyter type whos
to see alist of variables and their types)
That works because the object they are using (in this case numpy array) overloads the __getitem__
method. See this toy example:
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])
In python, []
is __getitem__
, which can be easily rewritten.
And, 1, 2
in python will give us a tuple. yes, we don’t really need ()
to create a non empty tuple.
So, Numpy can do this very easily, even I can.
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
You can use below code to try on your own 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]