Python中的分片(slice)问题?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python中的分片(slice)问题?相关的知识,希望对你有一定的参考价值。

在Python的官方文档(《The Python Language Reference, Release 3.2》)中的第“5.3.3 Slicings”小节中给出了分片的定义,如下:
slicing ::= primary "[" slice_list "]"
slice_list ::= slice_item ("," slice_item)* [","]
slice_item ::= expression | proper_slice
proper_slice ::= [lower_bound] ":" [upper_bound] [ ":" [stride] ]
lower_bound ::= expression
upper_bound ::= expression
stride ::= expression

从第三行到第七行我们知道,在分片(slice)中也支持索引(index)操作。在该小节当中,文档指出:任何下标(subscription,我们也可以索引index;正如在C/C++中,索引和下标是一个意思)能够被当作一个分片来解析。在“5.3.2 Subscriptions“中文档又指出:对于一个序列类型运用下标操作时,下标表达式必须计算为一个整数或分片。所以,我们可以认为,下标是一个特殊的分片;我们在这把上述定义中的索引和分片统称为分片。

所以,在上述分片定义中,使用的语法就是分片(我们认为索引是特殊的分片)。

现在,我们再来看第一行和第二行。第一行很好理解。对于第二行,根据BNF法则(Python定义语法时使用的法则),我们可以理解为:在使用分片时,可以使用用逗号隔开的一个或多个(至少一个)分片。

这时,我们给出一个例子。如下:
>>>a="1234567890"
>>>a[0],a[1],a[2]
>>>a[0,1,2]
>>>a[0:2,1:3,3:-1]
>>>a[0,1,2:-1]

经过以上的分析,我们应该由理由知道:上面给出的例子,都应该是正确的。但是,在使用时,只有第二行(a[0],a[1],a[2])是对的,其他的都提示说语法错误(抛出TypeError异常)。这是为什么呢?难道是我理解错了?我是根据“分片定义”中的第二行理解的,才得出的这个结果。如果我理解错了,那这句应该怎样理解?

另外,在内置类型当中,分片是对于序列类型(包括string, list, tuple三种)和映射类型(只有dictionay一种);换句话说,序列类型和映射类型都是支持分片,都能使用分片操作。但在第5.3.3小节当中的最后一段的第一前两名如下:“The semantics for a slicing are as follows. The primary must evaluate to a mapping object, and it is indexed (using the same __getitem__()method sa normal subscription) with a key that is constructed from the slice list.” 我们可以从这句话中得出,分片只支持映射类型,因为primary必须被计算为一个属于映射类型的对象。这又是为什么?前后是不是很矛盾?

在以上问题当中,正确的理解是什么?

1 一般的分片是针对python中的标准list等类型来说的 ;而string是一个有点特殊的list ,最好用一般的list比如 data = [1,2,3,4,5,6],str是个特例,它是str类型,其实已经封装为一个内置对象了;

2 至于你给出的例子,我倒是想起了matlab;一般我都是用py里的分片 d[1:5:2]或者d[5:1:-2] 这样

3 分片的时候一定要是整形,也就是integer,不管是list还是str !追问

你说的我也明白,不过,按照语法,分片基本上操作的对象是序列型的,而字符串也是序列型的一种。退一步来说,就算不适应于str型的,那list型的应该可以吧?!我试了一下,同样是错误的!也就是说,上面列出的例子不论是str型的还是list型的,只要是序列型的,都是错误的。难道官方文档中的定义错了?还是我理解错了,不该这么用?如果真是这样的话,那么官方文档就要修改一下,不然这很容易让人误解!希望官方文档没有错!

追答

1 python本质上是一种语言规范和设计,而在具体实现的时候是要有所权衡的,这也是为什么会有cpython, jython,甚至pypy的原因之一;
2 你提到slice中保存的部分,就语言实现来说,其实内置类型都不支持;只有在特定场合比如使用LX提到的numpy等模块时,才会用到;而且这种用法个人也觉得可能来自于matlab等计算机代数系统中的矩阵操作。
3 可否提供你所参考的文档具体URL ?

参考资料:http://docs.python.org/tutorial/introduction.html#lists

参考技术A 这个语法不是这么用的,事实上这种slice_list极少用到,除非你要进行矩阵计算时看上去好看些,但不用它你也可以实现矩阵计算。
>>>import numpy
>>> a = numpy.matrix([[1,2,3],[4,5,6],[7,8,9]])
matrix([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])

>>> a[0:2,1:3]
matrix([[2, 3],
[5, 6]])
事实上上面的效果你用个循环很容易做出来,这种语法糖只是好看点。

一般你最多也就用到a[10:0:-2]了,足够了。追问

我也知道,而且我以前也从来没有见过有谁这样用过。我只不过是在看官方文档时,根据它的定义自己理解的:按照它的定义,这样的语法也应该可以接受;既然可以接受,那也就能够运行,而不会成为一个错误。对于这样的语法,在序列类型上使用时,问题错的。
另外,我的这个问题是针对官方文档在定义内置类型(序列型的类型)上的操作的,不是其他模块中定义的类型的操作。

参考技术B
参考技术C

Python 数据类型中的“冒号“[::]----分片与步长

例如:

string = "what the fuck^_^" 

可以使用分片符和步长符:来给字符串进行分片和定义步长

string = "what the fuck^_^" 
#默认返回全部
print string[:]

#返回1到9结果
print string[1:9]

#返回1到9结果,步长为1
print string[1:9:]

#返回1到9结果,步长为2
print string[1:9:2]

#返回1到9结果,步长为-1
print string[1:9:-1]

#转置
print string[::-1]

结果如下:

技术分享

这里发现

#返回1到9结果,步长为-1
print string[1:9:-1]

没有输出1到9的逆序,这时将string[1:9]看成第一个字符串,然后转置就行了

#返回1到9结果,步长为-1
print string[1:9][::-1]

 

技术分享

用这个方法判断某个字符串的子串是否为回文串就很有灵性了

 

以上是关于Python中的分片(slice)问题?的主要内容,如果未能解决你的问题,请参考以下文章

python slice 分片(切片)

Python 中的 slice() 函数有啥作用?

Nginx 用分片提示缓存效率

Python中的分片和索引方法

Python 数据类型中的“冒号“[::]----分片与步长

python3.5修炼手册6