当前位置:   article > 正文

*args以及**kwargs的理解_*args和**kwargs安全

*args和**kwargs安全

今天在学习《数据结构(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).......
  • 1
  • 2

错误复现(选看)

刚开始自己并没有看这个文档,也没关心,在实现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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
'
运行

于是在实现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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

于是就开始报错

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):  ....
  • 1
  • 2

并且从上面可以知道,以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
  • 1
  • 2
  • 3
  • 4
  • 5
'
运行

其中第一个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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/963805
推荐阅读
相关标签
  

闽ICP备14008679号