【问题标题】:What's the difference between list[::] and list?list[::] 和 list 有什么区别?
【发布时间】:2018-09-17 01:40:40
【问题描述】:

这是一个将矩阵顺时针旋转 90 度的问题,我不明白为什么我不能使用:

matrix = zip(*matrix[::-1])

但是:

class Solution:
    def rotate(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: void Do not return anything, modify matrix in-place instead.
        """
        matrix[::] = zip(*matrix[::-1])

【问题讨论】:

  • 一个重新绑定名称,另一个在现有对象上调用__setitem__
  • [:][::] 相同。

标签: python arrays python-3.x list


【解决方案1】:

matrix 在您的方法中是对矩阵对象的引用。分配给matrix 将更改matrix 以引用您新创建的对象,但不会更改原始对象的内容。 matrix[::] =matrix 引用的对象上调用 __setitem__,从而相应地更改对象的内容。

【讨论】:

  • 看起来更像是一个二维列表而不是矩阵。文档字符串证实了这一点
【解决方案2】:

在 Python 中,所有赋值都将引用绑定到名称。运算符调用现有引用的方法1。在你的情况下,声明

matrix = ...

纯粹是一个任务2。它计算右侧,并将其绑定到本地函数范围内的名称matrix。无论您传入 matrix 时引用的任何对象都不会被触及。

这就是您看不到所做更改的原因。并不是该函数不能以这种方式工作,而是它对旋转列表没有任何作用。一旦函数退出,数据就会被丢弃。

操作

matrix[:] = ...

另一方面,不是语义上的赋值,尽管=符号3。这是给matrix.__setitem__(...)4 的电话。 __setitem__ 方法与任何其他方法一样,直接对对象进行操作,而无需更改其名称绑定。

就索引而言,[:] 等同于 [::]。它们分别是[0:len(matrix)][0:len(matrix):1] 的简写。在这两种情况下,都将使用默认步长。通常,任何带有冒号的索引都将转换为slice 对象。缺少的元素设置为None,并替换为此处显示的特定于序列的默认值。


1 一些运算符,如+=,在调用方法后执行赋值。这些被称为augmented assignments。但这不是我们现在感兴趣的案例。

2 除了字面量assignment statements (=),还有一些其他类型的赋值是def(将函数对象绑定到其名称)、class(其作用相同)对于类对象),import(将模块或模块元素绑定到名称),将参数传递给函数(将对象绑定到本地参数名称或 kwarg 字典键)和 for(其中在每次迭代时将一个元素从迭代器绑定到循环变量)。

3 从解析器的角度来看,它仍然是assignment,但语句的处理方式完全不同。一个实际上不是赋值的类似语句是在作为描述符实现的属性上使用= 运算符,例如property

4 从技术上讲,它更像是type(matrix).__setitem__(matrix, ...),但有一些额外的优化。例如,type(matrix) 的元类永远不会被搜索到。

【讨论】:

    猜你喜欢
    • 2010-10-15
    • 1970-01-01
    • 2011-05-04
    • 1970-01-01
    • 1970-01-01
    • 2019-03-15
    • 2011-04-07
    • 2020-08-20
    • 2012-09-26
    相关资源
    最近更新 更多