【问题标题】:Passing Python slice syntax around to functions将 Python 切片语法传递给函数
【发布时间】:2012-11-22 06:38:44
【问题描述】:

在 Python 中,是否可以完全封装常见的切片语法并传递它?我知道我可以使用slice__slice__ 来模拟切片。但我想传递与__getitem__ 一起使用的方括号中完全相同的语法。

例如,假设我编写了一个函数来返回列表的某个片段。

def get_important_values(some_list, some_condition, slice):
    elems = filter(some_condition, some_list)
    return elems[slice]

如果我手动传入一个切片对象,这会很好:

In [233]: get_important_values([1,2,3,4], lambda x: (x%2) == 0, slice(0, None))
Out[233]: [2, 4]

但我想让用户通过的是完全他们将使用__getitem__ 的相同切片:

get_important_values([1,2,3,4], lambda x: (x%2) == 0, (0:-1) )

# or

get_important_values([1,2,3,4], lambda x: (x%2) == 0, (0:) )

显然这会产生语法错误。但是有没有什么办法可以让这个工作,而不是为x:y:t 类型切片编写我自己的迷你解析器,并强制用户将它们作为字符串传递?

动机

我可以让这个示例函数返回直接可切片的内容,例如filter(some_condition, some_list),这将是一个列表的整个结果。然而在我的实际例子中,内部函数要复杂得多,如果我提前知道用户想要的切片,我可以大大简化计算。但我希望用户不必做太多额外工作来提前告诉我切片。

【问题讨论】:

  • 你写__getattr__的地方我猜你的意思是__getitem__
  • 是的,对不起。我将在上面进行编辑以修复它。
  • 如果 Python 有“切片文字”这样的东西,那就太酷了。我不认为破解该语言会太难,但我想这样的建议会被拒绝,因为几乎没有必要。
  • 对于numpy 用户,还有一个答案here 使用numpy.s_
  • 是否有为此被拒绝的 PEP?我发誓有,但我现在找不到。

标签: python syntax slice


【解决方案1】:

也许以下几行对你有用:

class SliceMaker(object):
  def __getitem__(self, item):
    return item

make_slice = SliceMaker()

print make_slice[3]
print make_slice[0:]
print make_slice[:-1]
print make_slice[1:10:2,...]

这个想法是您使用make_slice[] 而不是手动创建slice 的实例。通过这样做,您将能够充分使用熟悉的方括号语法。

【讨论】:

  • 这是个好主意。这比绕过切片的各个边界要干净得多。如果我不得不通过自己的切片输入来稍微增加用户的负担,我认为这是迄今为止建议中侵入性最小的。
  • 请注意,NumPy 已将其内置为 np.s_: docs.scipy.org/doc/numpy/reference/generated/numpy.s_.html
【解决方案2】:

简而言之,没有。该语法仅在 [] 运算符的上下文中有效。我可能会建议接受一个元组作为输入,然后将该元组传递给slice()。或者,也许您可​​以重新设计您正在做的任何事情,以便 get_important_values() 以某种方式实现为可切片对象。

例如,您可以执行以下操作:

class ImportantValueGetter(object):
    def __init__(self, some_list, some_condition):
        self.some_list = some_list
        self.some_condition = some_condition

    def __getitem__(self, key):
        # Here key could be an int or a slice; you can do some type checking if necessary
        return filter(self.some_condition, self.some_list)[key]

您可能可以通过将其变成某种容器 ABC 来做得更好,但这是一般的想法。

【讨论】:

  • 如何模拟[] 的上下文?此外,元组也可以工作。但是我不喜欢区分使用 None 来暗示(获取所有内容)与仅忽略该选项之间的区别。如果slice 采用关键字,它可能会变得更好。
  • 另外,如果我只是想让get_important_values 直接可切片,我会直接返回filter(some_condition, some_list),这将是一个列表的整个结果。在我的实际示例中,内部函数要复杂得多,如果我提前知道用户想要的切片,我可以大大简化计算。但我希望用户不必做太多额外的事情来提前告诉我切片。
  • 您仍然可以使用此示例执行此操作。在__getitem__ 中,如果keyslice(使用isinstance(key, slice),那么您可以访问切片对象的所有开始、停止和步进属性,并在将其直接应用于过滤结果。
  • 我同意你的观点,我可以这样做,这是一个有用的主题,在这种设计更适合的其他情况下,请记住这一点。
【解决方案3】:

一种方法(对于简单切片)是让切片参数是 dict 或 int,

get_important_values([1, 2, 3, 4], lambda x: (x%2) == 0, {0: -1})

get_important_values([1, 2, 3, 4], lambda x: (x%2) == 0, 1)

那么语法将或多或少保持不变。

这行不通,因为当你想做类似的事情时

some_list[0:6:10..]

【讨论】:

    猜你喜欢
    • 2018-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-22
    • 1970-01-01
    • 2017-09-18
    • 2013-10-12
    • 2017-02-10
    相关资源
    最近更新 更多