wim*_*wim 11 python arrays numpy list slice
虽然我发现负数环绕(即A[-2]
索引倒数第二个元素)在许多情况下非常有用,但当它发生在切片内时,它通常比一个有用的功能更令人烦恼,我经常希望有一种方法禁用该特定行为.
这是下面的一个罐装2D示例,但我与其他数据结构和其他维度的数量相同.
import numpy as np
A = np.random.randint(0, 2, (5, 10))
Run Code Online (Sandbox Code Playgroud)
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()
Run Code Online (Sandbox Code Playgroud)
在上面的切片中,我宁愿切片的任何负数都将被视为相同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()
Run Code Online (Sandbox Code Playgroud)
我还尝试对数组或列表进行零填充,但它仍然不够优雅(需要相应地调整查找位置索引)并且效率低(需要复制数组).
我错过了一些像这样切片的标准技巧或优雅解决方案吗?我注意到python和numpy已经处理了一个很好地指定太大数字的情况 - 也就是说,如果索引大于数组的形状,它的行为就像它一样None
.
我的猜测是您必须围绕所需的对象创建自己的子类包装器并重新实现__getitem__()
以将负键转换为None
,然后调用超类__getitem__
请注意,我的建议是对现有的自定义类进行子类化,而不是像list
或dict
. 这只是为了围绕另一个类创建一个实用程序,而不是混淆一个list
类型的正常预期操作。这将是您想要在特定上下文中使用一段时间直到您的操作完成的东西。最好避免进行全局不同的更改,这会使代码的用户感到困惑。
目的。getitem (self, key)
调用以实现对 self[key] 的评估。对于序列类型,接受的键应该是整数和切片对象。请注意,负索引的特殊解释(如果类希望模拟序列类型)取决于 getitem () 方法。如果 key 的类型不合适,可能会引发 TypeError;如果序列的索引集之外的值(在对负值进行任何特殊解释之后),则应该引发 IndexError 。对于映射类型,如果缺少 key(不在容器中),则应引发 KeyError。
您甚至可以创建一个包装器,该包装器仅将实例作为参数,并将所有__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
Run Code Online (Sandbox Code Playgroud)