【问题标题】:Python slice how-to, I know the Python slice but how can I use built-in slice object for it?Python 切片操作方法,我知道 Python 切片,但是如何使用内置切片对象呢?
【发布时间】:2011-04-24 02:42:51
【问题描述】:

内置函数slice有什么用,如何使用?
我知道的 Pythonic 切片的直接方法 - l1[start:stop:step]。我想知道我是否有一个切片对象,那么我该如何使用它呢?

【问题讨论】:

  • 这对我有用。 def __slice__(self, start = None, end = None, step = None): return self.obj[slice(start, end, step)]

标签: python slice


【解决方案1】:

您可以通过调用 slice 来创建一个 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

【讨论】:

    【解决方案2】:

    序列后面的方括号表示索引或切片,具体取决于括号内的内容:

    >>> "Python rocks"[1]    # index
    'y'
    >>> "Python rocks"[1:10:2]    # slice
    'yhnrc'
    

    这两种情况都由序列的__getitem__() 方法处理(或__setitem__(),如果在等号左侧)。索引或切片作为单个参数传递给方法,以及Python 通过将切片表示法(在本例中为1:10:2)转换为切片对象:slice(1,10,2)

    因此,如果您要定义自己的类序列类或覆盖另一个类的__getitem____setitem____delitem__ 方法,则需要测试索引参数以确定它是int 还是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 对象具有三个属性:startstopstep,以及一个方法:indices,它接受一个参数,即对象的长度,并返回一个三元组:(start, stop, step).

    【讨论】:

    【解决方案3】:
    >>> 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)),)
    >>>
    

    【讨论】:

    • 请参阅下面 Don 的回复,了解为什么会发生这种情况。
    • 还需要指出可以有多个切片传入__getitem__:s[1:2:3, 1, 4:5] => (slice(1, 2, 3), 1, slice(4, 5, None))
    • keys之前不使用解包运算符*,可能更容易看到[]中的索引或切片如何传递给特殊方法__getitem__()
    【解决方案4】:

    slice 函数返回slice objects。 Slice 对象是 Python 的内部类型之一,针对读取性能进行了优化 - 它们的所有属性都是只读的。

    如果希望更改默认行为,更改 slice 可能很有用。例如,lxml 使用切片表示法来访问 DOM 元素(但是,我还没有确认他们自己是如何做到的)。

    【讨论】:

      【解决方案5】:

      在尝试回答 Subset a string based on variable 时,我记得 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 现在是一个切片元组。

      【讨论】:

      • 实际上在这种情况下 np.s_[18:26] 只是返回一个 Python 切片对象,该对象与使用内置 slice 构造的对象相同。对于其他类型的 numpy-only 索引方法,它可能会有所不同。
      • 已添加,谢谢!但我将这个问题理解为如何在语法上表示切片。所以这是我所知道的最接近的。
      【解决方案6】:

      切片对象可让您以编程方式生成和操作切片。特别是对于多维 numpy 数组,尤其是如果您事先不知道维度,您可能需要即时构造切片以指定所需的轴或维度。

      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]])
      

      这里我们的数据最终是二维的(4×5),但不能保证这一点。您将如何向zz 请求切片?

      一个问题是我无法操作 Python 的切片符号。它不是切片操作之外的有效语法。

      my_slice = 2:3:1
      >>> SyntaxError: Invalid Syntax
      

      如果我可以在循环中构建我想要的确切切片请求,我可以构建一个字符串怎么办?那不是很好吗?我的意思是,当然你可以使用一个字符串来做,但它会很乱,需要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+"])
      

      所以我们在这里:slice 对象让你这样做。您可以即时组装它们的列表和元组,将它们作为函数参数传递,对它们进行排序,随机播放,等等。

      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]])
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-26
        • 2010-11-13
        相关资源
        最近更新 更多