赞
踩
今天在学习《数据结构(Python语言描述)》第四章 数组和链接结构 中的练习“提供一个把Grid类用作数据结构来实现三维array类的策略”。其中在实现这个三维array时,实现__getitem__以及__setitem__命令遇到了一些困惑的东西,其实问题的所在就是这个*args以及**kwargs两个参数,所以在此进行一个记录。
首先这两个命令的作用如下:
数组操作 | 方法名称 |
---|---|
a[index] = newItem | _setitem_(index, newItem) |
a[index] | _getitem_(index) |
而阅读这两个方法的源码:
def __getitem__(self, *args)........
def __setitem__(self, *args, **kwargs).......
刚开始自己并没有看这个文档,也没关心,在实现Array的命令如下,就很简单:
class Array(object):
...
def __getitem__(self, index):
return self.items[index]
def __setitem__(self, key, value):
"""因为这个数组是基于list而创建的,故直接定义即可"""
"""Subscript operator for replacement at index"""
self.items[key] = value
于是在实现Grid命令时,就遵从了如上思路:
# 错误的代码 class Grid(object): def __init__(self, rows, columns, fillvalue=None): self.data = Array(rows) for i in range(rows): self.data[i] = Array(columns, fillvalue=fillvalue) def __setitem__(self, row, col, value): """-> Supports two-dimensions index, like[row, column]""" self.data[row][col] = value def __getitem__(self, row, col): """-> Supports two-dimensions index, like[row, column]""" return self.data[row][col] if __name__ == "__main__": grid = Grid(5, 5) print(grid[3, 2]) grid[3, 2] = 10 print(grid)
于是就开始报错
TypeError: getitem() missing 1 required positional argument: ‘col’
以及
TypeError: setitem() missing 1 required positional argument: ‘value’
同时自己书写的三维array也会报错,具体代码忘了,但是写的很乱,依稀记着其提示为,需要一个整数而不是list这样子
首先必须理解,这两个命令定义时只能写:
def __getitem__(self, index): ...
def __setitem__(self, index, value): ....
并且从上面可以知道,以setitem为例,其中index代表的是*args
,而value代表的是**kwargs
,在这个c#中*
代表指针的意思,但是python中并没有指针,那么我现在理解例如from xxx import *
其中的代表的就是所有的意思,那么在这里就可以理解为,index
代表你输入的a[a,b,c,d....]
中输入的所有参数,他把他们一起打包成一个元组,这样进行传递。
所以我上面的代码不对,并且报错的原因是:grid[3, 2]
他就把3和2打包成一个元素,传递给命令中的row,而col没有值,所以就报错缺少col,第二个也同理。
这个练习给我最大的思考就是,Array是基础的数据结构,Grid就是建立在Array基础上的数据结构,3D就是建立在Grid基础上的数据结构,也可以说二维网格就是数组的数组,三维数组就是数组的数组的数组,以此套娃。
所以在建立三维数组的__getitem__以及__setitem__
命令的时候,就需要按照上面的思路进行了。我写的正确代码俯下,截取部分:
def __setitem__(self, index, value):
"""-> Supports two-dimensions index,
like[row, column, channel]
"""
self.data[index[2]][index[0], index[1]] = value
其中第一个index[2]
就是先去索引channel,其中每一个channel记录的就是一个Grid,然后后面是一个数组,其实就是访问一个Grid中的元素,即调用他的__setitem__
命令。其实如果继续思考,Grid中__setitem__
其实最终还是调用了Array中的__setitem__
,也就是基础了。
其中在重写__setitem__
命令时,我只写了一个index
,但是在实例化使用的时候,我可以任意往里面写参数,最终这个index都会把这些参数吃进来,我在使用即可,就不会乱掉了。所以以后自己再重写*args以及**kwargs
命令的时候,就不需要写很多标识符,而只需要去关注他的数据结构即可。
附录:
""" File:grid.py A grid with size [rows, columns] use getitem, getHeight, getWidth and str. To instantiate, use <variable> = Grid(<rows>, <columns>, <option for value>) The fill value is None by default. """ from arrays import Array class Grid(object): def __init__(self, rows, columns, fillvalue=None): self.data = Array(rows) for i in range(rows): self.data[i] = Array(columns, fillvalue=fillvalue) def getHeight(self): return len(self.data) def getWidth(self): return len(self.data[0]) def __setitem__(self, index, value): """-> Supports two-dimensions index, like[row, column]""" self.data[index[0]][index[1]] = value def __getitem__(self, index): """-> Supports two-dimensions index, like[row, column]""" return self.data[index[0]][index[1]] def __str__(self): """return the string format of the grid""" result = "" for row in range(self.getHeight()): for col in range(self.getWidth()): result += str(self.data[row][col]) + " " result += '\n' return result def searchNegativeNum(self): """Search the first negative number in the grid, if not, return the row and column number of the grid """ for row in range(self.getHeight()): for col in range(self.getWidth()): if self.data[row][col] is not None: if self.data[row][col] < 0: return [row, col] return [self.getHeight(), self.getWidth()] if __name__ == "__main__": grid = Grid(5, 5) grid[3, 2] grid[3, 2] = 10 print(grid)
from arrays import Array from grid import Grid class Grid3D(object): def __init__(self, rows, columns, channels, fillvalue=None): self.data = Array(channels) self.shape = [rows, columns, channels] for channel in range(channels): self.data[channel] = Grid(rows, columns, fillvalue=fillvalue) def __getitem__(self, index): """-> Supports three-dimensions index, like[row, column, channel]""" return self.data[index[2]][index[0], index[1]] def __setitem__(self, index, value): """-> Supports two-dimensions index, like[row, column, channel] """ self.data[index[2]][index[0], index[1]] = value def getChannel(self): return self.shape[2] def setPositionValue(self): """This will set the value with it position, example:potion(2,3,3) will set value of '233' """ for channel in range(self.shape[2]): for row in range(self.shape[0]): for col in range(self.shape[1]): self.data[channel][[row, col]] = str(row)+str(col)+str(channel) if __name__ == '__main__': a = Grid3D(5, 5, 3) # a.setPositionValue() print(a[3, 2, 2]) a[3, 2, 2] = 10 print(a[3, 2, 2]) print(a)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。