Python列表/数组:禁用负向索引换行

虽然我发现在很多情况下,负片数环绕(即A[-2]索引倒数第二个元素)非常有用,但当它发生在片内时,通常比有用的功能更麻烦,而且我经常希望有一种方法来禁用该特定行为。

下面是一个2D的封装示例,但是我已经和其他数据结构以及其他维度数量相同。

import numpy as np
A = np.random.randint(0, 2, (5, 10))

def foo(i, j, r=2):
  '''sum of neighbours within r steps of A[i,j]'''
  return A[i-r:i+r+1, j-r:j+r+1].sum()

在上面的片段中,我宁愿片的任何负数将被视为与None相同,而不是包装到数组的另一端。

由于包装的原因,上面的其他好的实现在边界条件下给出了不正确的结果,并且需要某种类型的补丁:

def ugly_foo(i, j, r=2):
  def thing(n):
    return None if n < 0 else n
  return A[thing(i-r):i+r+1, thing(j-r):j+r+1].sum()

我也尝试了零填充数组或列表,但它仍然不雅(需要相应地调整查找位置索引)并且效率低下(需要复制数组)。

我是否缺少一些像这样切片的标准技巧或优雅的解决方案? 我注意到,python和numpy已经处理好你指定的数字太大的情况 - 也就是说,如果索引大于数组的形状,则它的行为与None


我的猜测是,你将不得不围绕期望的对象创建你自己的子类包装,并重新实现__getitem__()将负键转换为None ,然后调用超类__getitem__

请注意,我所建议的是将现有的自定义类进行子类化,而不是像listdict一样dict 。 这只是为了围绕另一个类创建实用程序,而不是混淆list类型的正常预期操作。 这将是你想在特定环境中使用一段时间直到你的操作完成。 最好避免进行全球不同的更改,这会使代码的用户感到困惑。

数据模型

目的。 getitem (自我,关键)
被称为实施自我评估[关键]。 对于序列类型,接受的键应该是整数和切片对象。 请注意,负指数的特殊解释(如果类希望模拟序列类型)取决于getitem ()方法。 如果密钥的类型不合适,则可能会引发TypeError; 如果对于序列的索引集合之外的值(在负值的任何特殊解释之后),应该引发IndexError。 对于映射类型,如果键缺失(不在容器中),应该引发KeyError。

你甚至可以创建一个简单的实例作为arg,并且只是将所有__getitem__()调用都推迟到该私有成员,同时转换密钥(对于不能或不想要子类型的情况)而只需要一个用于任何序列对象的实用包装。

后一个建议的简单例子:

class NoWrap(object):

    def __init__(self, obj, default=None):
        self._obj = obj 
        self._default = default

    def __getitem__(self, key):
        if isinstance(key, int):
            if key < 0:
                return self._default

        return self._obj.__getitem__(key)

In [12]: x = range(-10,10)
In [13]: x_wrapped = NoWrap(x)
In [14]: print x_wrapped[5]
-5
In [15]: print x_wrapped[-1]
None 
In [16]: x_wrapped = NoWrap(x, 'FOO')
In [17]: print x_wrapped[-1]
FOO

虽然你可以像jdi所建议的那样listlist ,但是Python的切片行为并不是任何人希望你沉溺的东西。

改变它可能会导致其他人在使用你的代码时发生一些严重的头疼,当它不像预期的那样行事时 - 并且可能需要一段时间,然后才会查看你的子类的特殊方法,以查看实际发生的事情上。

请参阅:在远处采取行动


我认为这不足以证明新课程和包装事物的合理性。 然后再次它是你的代码。

def foo(i, j, r=2):
  '''sum of neighbours within r steps of A[i,j]'''
  return A[i-r:abs(i+r+1), j-r:abs(j+r+1)].sum()   # ugly, but works?

(Downvoting很有趣,所以我增加了一些选项)

我发现了一些非常意想不到的事情(对我来说): __getslice__(i,j)不包装! 相反,负指数被忽略,所以:

lst[1:3] == lst.__getslice__(1,3)

lst[-3:-1] == 2 next to last items lst.__getslice__(-3,-1) == [] lst[-3:-1] == 2 next to last items但是lst.__getslice__(-3,-1) == []

最后:

lst[-2:1] == [] ,但是lst.__getslice__(-2,1) == lst[0:1]

令人惊讶,有趣,完全无用。

链接地址: http://www.djcxy.com/p/26753.html

上一篇: Python lists/arrays: disable negative indexing wrap

下一篇: How Python String array work?