numpy.ndarray:转换为“普通”类

6 投票
3 回答
2047 浏览
提问于 2025-04-16 10:22

[Python 3]

我喜欢用 ndarray,但是用起来有点烦。

我遇到一个问题。我想写一个 class Array,这个类能继承 ndarray 的很多功能,但它只能以一种方式创建:就是生成一个填满零的特定大小的数组。我本来想这样写:

class Array(numpy.ndarray):
  def __init__(size):
    # What do here?

我想用 super().__init__ 来传一些参数,创建一个填满零的数组,但这行不通,因为 ndarray 是用一个全局函数 numpy.zeros 来创建填满零的数组,而不是用构造函数。

问题:

  1. 为什么在很多情况下,ndarray 会使用全局(模块)函数,而不是构造函数?如果我想在面向对象的环境中重用它们,这就很麻烦。

  2. 我需要的 class Array 最好怎么定义?我是不是应该手动把 ndarray 填充为零,还是有其他方法可以重用 zeros 函数?

3 个回答

4

ndarray的继承有点复杂。ndarray 甚至没有 __init(self, )___ 这个方法,所以它不能被子类调用,但这样设计是有原因的。你可以查看numpy的文档,了解子类化的相关内容。

顺便问一下,你能具体说说你的需求吗?其实创建一个利用ndarray的类还是很简单的,但要创建一个继承自ndarray的子类,以便使用numpy的所有功能,那就复杂多了。

我似乎无法对自己的帖子评论,真奇怪
@Philipp:这个方法会被Python调用,但不会被numpy调用。创建ndarray的方式有三种,如何处理这三种情况的指导可以在那个文档中找到。

9

为什么ndarray在很多情况下使用全局(模块)函数而不是构造函数呢?

  1. 为了和Matlab兼容,像zerosones这样的函数最初就是从那里来的。
  2. 全局工厂函数写起来快,理解起来也简单。构造函数应该有什么样的语义呢?比如,怎么用一个构造函数来表示简单的zerosemptyones呢?实际上,这种工厂函数在其他编程语言中也很常见。

我需要定义class Array,最好的方法是什么?

import numpy

class Array(numpy.ndarray):
    def __new__(cls, size):
        result = numpy.ndarray.__new__(Array, size)
        result.fill(0)
        return result
arr = Array(5)

def test(a):
    print type(a), a

test(arr)
test(arr[2:4])
test(arr.view(int))

arr[2:4] = 5.5

test(arr)
test(arr[2:4])
test(arr.view(int))

注意这是Python 2,但只需要做一些小修改就能在Python 3中使用。

7

如果你不喜欢 ndarray 这个接口,那就别去继承它。你可以自己定义一个接口,然后把其他的事情交给 ndarraynumpy 来处理。

import functools
import numpy as np


class Array(object):

    def __init__(self, size):
        self._array = np.zeros(size)

    def __getattr__(self, attr):
        try: return getattr(self._array, attr)
        except AttributeError:
            # extend interface to all functions from numpy
            f = getattr(np, attr, None)
            if hasattr(f, '__call__'):
                return functools.partial(f, self._array)
            else:
                raise AttributeError(attr)

    def allzero(self):
        return np.allclose(self._array, 0)


a = Array(10)
# ndarray doesn't have 'sometrue()' that is the same as 'any()' that it has.
assert a.sometrue() == a.any() == False
assert a.allzero()

try: a.non_existent
except AttributeError:
    pass
else:
    assert 0

撰写回答