【问题标题】:numpy.ndarray: converting to a "normal" classnumpy.ndarray:转换为“普通”类
【发布时间】:2011-06-13 01:23:44
【问题描述】:

[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 函数?

【问题讨论】:

  • 我不明白你为什么要创建自己的课程。与numpy.zeros() 工厂函数相比有什么优势?如果你不喜欢这个名字,只需重命名它,比如create_array = numpy.zeros
  • 我不再确定是否有优势。也许我只是不习惯工厂功能。我得考虑一下。
  • @Sven Marnach:我找到了几个关于这个一般主题的链接:stackoverflow.com/questions/628950/…stackoverflow.com/questions/2959871/…stackoverflow.com/questions/4617311/… 没有特定于 Python,但其他语言的一般 cmets 似乎适用。据我所知,工厂功能确实没有缺点(除了我个人的喜好)。

标签: python numpy python-3.x wrapper


【解决方案1】:

为什么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。

【讨论】:

  • 一些注意事项: 1. ndarray 构造函数的shape 参数可能只是一个整数而不是一个元组。 2. dtype=float 是默认值。 3. 在 Python 3 中,在这种情况下,您可以省略 super() 的参数。结合这些注释,构造函数的前两行简化为super().__init__(size)
  • 哦,我刚刚注意到您的 super() 调用是错误的——在 Python 2.x 中应该是 super(Array, self)
  • 你说得对,我已经编辑了我的答案。 (像往常一样,构造函数签名没有记录。)
  • @Philipp:它记录在类的文档字符串中,而不是构造函数本身。但这实际上是文档所属的地方。
  • @Sven:我的意思是文档说shape 必须是一个元组,而不是说dtype 默认为float
【解决方案2】:

如果您不喜欢ndarray 接口,请不要继承它。您可以定义自己的接口并将其余部分委托给 ndarray 和 numpy。

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

【讨论】:

  • 非常整洁。我假设所有numpy 全局函数在使用ndarray 参数作为ndarray 的同名实例方法调用时具有相同的语义。
  • 要更改为 Python 3,我只需从类定义中删除 (object),对吗? [并不是说离开它会导致问题。]
  • @max:代码在 2.x 和 Python 3 上都可以正常工作。
  • 我似乎在这里遗漏了一些东西。您不是从ndarray 派生的,但是如果请求了任何属性,您首先尝试从ndarray 实例中获取该属性。首先从ndarray 派生不是更容易吗?您仍然可以添加魔法以将 numpy 中的模块级函数添加为方法,但我认为这也不是一个好主意,因为它们中的大多数 已经是方法,其余的则不是作为一种方法是有意义的(很少有例外)。
  • @Sven Marnach:前提是 OP 觉得 ndarray 使用起来很烦人。委托是一种比继承更灵活的更改类接口的方法。该代码不是最终解决方案,而只是一个框架示例,允许对其进行扩展以使用黑名单、白名单方法等。我同意模块级功能。该代码显示了如何您可以做到这一点;它并不主张这样做是明智的。
【解决方案3】:

ndarray 的继承有点棘手。 ndarray 甚至没有 __init(self, )___ 方法,所以它不能从子类中调用,但这是有原因的。请参阅subclassing 的 numpy 文档。

顺便问一下,您能否更具体地说明您的特定需求?为自己的需要编写一个类(使用 ndarray)仍然很容易,但是通过所有 numpy 机制的 ndarray 子类是完全不同的问题。

我好像不能评论我自己的帖子,奇怪
@Philipp:它将由 Python 调用,但不会由 numpy 调用。实例化 ndarray 有三种方法,该文档中给出了如何处理所有情况的指南。

【讨论】:

  • 我好像错过了这份文件。但是为什么在我的示例中调用__init__ 方法,即使ndarray__new__
  • @Philipp:请参阅我对您的回答的评论。
  • 我只想要我自己的类,我可以完全控制它的实例化方式。你说得对,继承 ndarray 太难了。我将遵循@J.F. 中的容器方法。塞巴斯蒂安。
猜你喜欢
  • 2019-05-21
  • 2017-07-29
  • 2018-06-07
  • 2020-02-25
  • 1970-01-01
  • 2021-06-10
  • 2018-06-13
  • 2018-11-21
相关资源
最近更新 更多