Pythonic方式有"大小安全"切片

kas*_*syc 7 python slice

以下是/sf/users/62541/Explain Python的切片表示法的回答.

如果项目少于您的要求,Python对程序员很友好.例如,如果您要求[: - 2]并且只包含一个元素,则会得到一个空列表而不是错误.有时您会更喜欢错误,因此您必须意识到这可能会发生.

因此,当错误出现时,Pythonic的方法是什么?是否有更多的Pythonic方法来重写这个例子?

class ParseError(Exception):
    pass

def safe_slice(data, start, end):
    """0 <= start <= end is assumed"""
    r = data[start:end]
    if len(r) != end - start:
        raise IndexError
    return r

def lazy_parse(data):
    """extract (name, phone) from a data buffer.
    If the buffer could not be parsed, a ParseError is raised.

    """

    try:
        name_length = ord(data[0])
        extracted_name = safe_slice(data, 1, 1 + name_length)
        phone_length = ord(data[1 + name_length])
        extracted_phone = safe_slice(data, 2 + name_length, 2 + name_length + phone_length)
    except IndexError:
        raise ParseError()
    return extracted_name, extracted_phone

if __name__ == '__main__':
    print lazy_parse("\x04Jack\x0A0123456789") # OK
    print lazy_parse("\x04Jack\x0A012345678") # should raise ParseError
Run Code Online (Sandbox Code Playgroud)

编辑:使用字节字符串编写的示例更简单但我的实际代码使用列表.

Dun*_*can 5

这是一种可以说更像Pythonic的方式.如果要解析字节字符串,可以使用struct为此目的提供的模块:

import struct
from collections import namedtuple
Details = namedtuple('Details', 'name phone')

def lazy_parse(data):
    """extract (name, phone) from a data buffer.
    If the buffer could not be parsed, a ParseError is raised.

    """
    try:
        name = struct.unpack_from("%dp" % len(data), data)[0]
        phone = struct.unpack_from("%dp" % (len(data)-len(name)-1), data, len(name)+1)[0]
    except struct.error:
        raise ParseError()
    return Details(name, phone)
Run Code Online (Sandbox Code Playgroud)

我仍然发现untythonic是关于扔掉有用的struct.error回溯来替换ParseError的原因:原始告诉你字符串有什么问题,后者只告诉你出错了.


unu*_*tbu 3

使用像 safe_slice 这样的函数比创建一个对象来执行切片要快,但是如果速度不是瓶颈并且您正在寻找更好的接口,您可以定义一个带有 a 的类来在__getitem__返回切片之前执行检查。

这允许您使用漂亮的切片表示法,而不必将startstop参数都传递给safe_slice.

class SafeSlice(object):
    # slice rules: http://docs.python.org/library/stdtypes.html#sequence-types-str-unicode-list-tuple-bytearray-buffer-xrange
    def __init__(self,seq):
        self.seq=seq
    def __getitem__(self,key):
        seq=self.seq
        if isinstance(key,slice):
            start,stop,step=key.start,key.stop,key.step
            if start:
                seq[start]
            if stop:
                if stop<0: stop=len(seq)+stop
                seq[stop-1]
        return seq[key]

seq=[1]
print(seq[:-2])
# []
print(SafeSlice(seq)[:-1])
# []
print(SafeSlice(seq)[:-2])
# IndexError: list index out of range
Run Code Online (Sandbox Code Playgroud)

如果速度是一个问题,那么我建议只测试端点而不是进行算术。Python 列表的项目访问时间复杂度为 O(1)。下面的版本safe_slice还允许您传递 2,3 或 4 个参数。只有 2 个参数时,第二个参数将被解释为停止值(类似于range)。

def safe_slice(seq, start, stop=None, step=1):
    if stop is None:
        stop=start
        start=0
    else:
        seq[start]
    if stop<0: stop=len(seq)+stop
    seq[stop-1]        
    return seq[start:stop:step]
Run Code Online (Sandbox Code Playgroud)