内置函数有什么用slice
,如何使用?
我知道的 Pythonic 切片的直接方式 - l1[start:stop:step]
. 我想知道我是否有一个切片对象,那么我该如何使用它呢?
6 回答
您可以通过调用 slice 来创建切片,使用的字段与执行 [start:end:step] 表示法时使用的字段相同:
sl = slice(0,4)
要使用切片,只需将其作为索引传递到列表或字符串中:
>>> s = "ABCDEFGHIJKL"
>>> sl = slice(0,4)
>>> print(s[sl])
'ABCD'
假设您有一个固定长度的文本字段文件。您可以定义一个切片列表,以便轻松地从该文件中的每个“记录”中提取值。
data = """\
0010GEORGE JETSON 12345 SPACESHIP ST HOUSTON TX
0020WILE E COYOTE 312 ACME BLVD TUCSON AZ
0030FRED FLINTSTONE 246 GRANITE LANE BEDROCK CA
0040JONNY QUEST 31416 SCIENCE AVE PALO ALTO CA""".splitlines()
fieldslices = [slice(*fielddef) for fielddef in [
(0,4), (4, 21), (21,42), (42,56), (56,58),
]]
fields = "id name address city state".split()
for rec in data:
for field,sl in zip(fields, fieldslices):
print("{} : {}".format(field, rec[sl]))
print('')
# or this same code using itemgetter, to make a function that
# extracts all slices from a string into a tuple of values
import operator
rec_reader = operator.itemgetter(*fieldslices)
for rec in data:
for field, field_value in zip(fields, rec_reader(rec)):
print("{} : {}".format(field, field_value))
print('')
印刷:
id : 0010
name : GEORGE JETSON
address : 12345 SPACESHIP ST
city : HOUSTON
state : TX
id : 0020
name : WILE E COYOTE
address : 312 ACME BLVD
city : TUCSON
state : AZ
id : 0030
name : FRED FLINTSTONE
address : 246 GRANITE LANE
city : BEDROCK
state : CA
id : 0040
name : JONNY QUEST
address : 31416 SCIENCE AVE
city : PALO ALTO
state : CA
序列后面的方括号表示索引或切片,具体取决于括号内的内容:
>>> "Python rocks"[1] # index
'y'
>>> "Python rocks"[1:10:2] # slice
'yhnrc'
这两种情况都由__getitem__()
序列的方法处理(或者__setitem__()
如果在等号的左侧)。索引或切片作为单个参数传递给方法,Python 执行此操作的方式是转换切片表示法, ( 1:10:2
, 在这种情况下) 到切片对象: slice(1,10,2)
.
因此,如果您要定义自己的类序列类或覆盖另一个类的__getitem__
or__setitem__
或__delitem__
方法,则需要测试 index 参数以确定它是否为 anint
或 a slice
,并相应地进行处理:
def __getitem__(self, index):
if isinstance(index, int):
... # process index as an integer
elif isinstance(index, slice):
start, stop, step = index.indices(len(self)) # index is a slice
... # process slice
else:
raise TypeError("index must be int or slice")
一个slice
对象具有三个属性:start
、stop
和step
,以及一个方法:indices
,它接受一个参数,即对象的长度,并返回一个三元组:(start, stop, step)
。
>>> class sl:
... def __getitem__(self, *keys): print keys
...
>>> s = sl()
>>> s[1:3:5]
(slice(1, 3, 5),)
>>> s[1:2:3, 1, 4:5]
((slice(1, 2, 3), 1, slice(4, 5, None)),)
>>>
在尝试基于 variable 回答 Subset a string 时,我记得 numpy 有一种语法上很好的方式来定义切片对象:
>>> import numpy as np
>>> s = "The long-string instrument is a musical instrument in which the string is of such a length that the fundamental transverse wave is below what a person can hear as a tone."
>>> z = np.s_[18:26] # in this case same as slice(18, 26, None)
>>> s[z]
'strument'
这里解决的问题是如何将切片存储在变量中以供以后使用,并np.s_
允许这样做。是的,它不是内置的,但由于原来的问题被重定向到这里,我觉得我的答案也属于这里。此外,numpy 也是 Python IIRC 中添加如此高级切片功能的原因之一。
更复杂的“切片”示例:
>>> data = np.array(range(6)).reshape((2, 3))
>>> z = np.s_[:1, 1:2]
>>> data[z]
array([[1]])
>>> data
array([[0, 1, 2],
[3, 4, 5]])
>>> z
(slice(None, 1, None), slice(1, 2, None))
其中 z 现在是切片的元组。
Slice objects let you programmatically generate and manipulate slices. Especially for multidimensional numpy arrays, and especially if you don't know the dimensionality in advance, you might want to construct slices on-the-fly to specify the axes or dimensions that you want.
import numpy as np
dimension = np.random.randint(10) # Might have up to 10 dimensions
shape = []
for d in range(dimension):
shape.append(np.random.randint(10))
zz = np.random.rand(tuple(shape))
print(zz)
>>> array([[0.68379351, 0.50854469, 0.64578775, 0.73441699, 0.28977396],
[0.88797164, 0.81603025, 0.63978659, 0.22677299, 0.93455738],
[0.0892855 , 0.28048706, 0.04262895, 0.9353467 , 0.13062249],
[0.88561035, 0.93378367, 0.12124208, 0.25600301, 0.96035638]])
Here our data ended up being two dimensional (4-by-5), but there was no guarantee of that. How will you request slices from zz
?
One problem is that I can't manipulate Python's slice notation. It's not valid syntax outside of a slicing operation.
my_slice = 2:3:1
>>> SyntaxError: Invalid Syntax
What if I could just build up the exact slice request I wanted in a loop, the way I can build up a string? Wouldn't that be great? I mean, sure you can use a string to do it, but it would be messy and requires eval
.
your_slice_definitions = [(2,3,1), *[(None, None, None)]*(zz.ndim - 1)]
my_slice_str = ""
for slice_start, slice_end, slice_step in your_slice_definitions:
my_slice_str += "{}:{}:{},".format(slice_start, slice_end, slice_step)
eval("zz["+my_slice_str+"])
So here we are: slice
objects let you do this. You can assemble lists and tuples of them on-the-fly, pass them as function parameters, sort them, shuffle them, and so on.
my_slices = []
for slice_start, slice_end, slice_step in your_slice_definitions:
my_slices += slice(slice_start, slice_end, slice_step)
print(zz[my_slices])
>>> array([[0.0892855 , 0.28048706, 0.04262895, 0.9353467 , 0.13062249]])