以下是/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)
编辑:使用字节字符串编写的示例更简单但我的实际代码使用列表.
这是一种可以说更像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的原因:原始告诉你字符串有什么问题,后者只告诉你出错了.
使用像 safe_slice 这样的函数比创建一个对象来执行切片要快,但是如果速度不是瓶颈并且您正在寻找更好的接口,您可以定义一个带有 a 的类来在__getitem__返回切片之前执行检查。
这允许您使用漂亮的切片表示法,而不必将start和stop参数都传递给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)