NumPy基础知识(九)

本文详细介绍了NumPy中ndarray子类化的概念和机制,包括子类化的原因、对象创建的不同方式、视图转换与模板创建的关系,以及如何在子类中添加额外属性。此外,还探讨了子类化与ufuncs的交互以及潜在的陷阱,强调了子类化时保持向下兼容性的重要性。
摘要由CSDN通过智能技术生成

NumPy基础知识(九)

 

子类ndarray 

简介

ndarray的子​​类化相对简单,但是与其他Python对象相比,它具有一些复杂性。在此页面上,我们解释了允许您对ndarray进行子类化的机制,以及实现子类的含义。

ndarrays和对象创建

ndarray的子​​类化很复杂,因为ndarray类的新实例可以以三种不同的方式出现。这些是:

  1. 显式构造函数调用-如中所述MySubClass(params)。这是创建Python实例的常用方法。

  2. 视图转换-将现有的ndarray转换为给定的子类

  3. 模板新功能-从模板实例创建新实例。示例包括从子类数组返回切片,从ufunc创建返回类型以及复制数组。有关更多详细信息,请参见 从模板创建新内容。

最后两个是ndarray的特征-为了支持数组切片之类的事情。ndarray子类化的复杂性归因于numpy必须支持后两种实例创建路径的机制。

查看铸造

视图转换是标准的ndarray机制,通过该机制,您可以获取任何子类的ndarray,并将该数组的视图作为另一个(指定的)子类返回:

>>>
>>> import numpy as np
>>> # create a completely useless ndarray subclass
>>> class C(np.ndarray): pass
>>> # create a standard ndarray
>>> arr = np.zeros((3,))
>>> # take a view of it, as our useless subclass
>>> c_arr = arr.view(C)
>>> type(c_arr)
<class 'C'>

从模板创建新的

当numpy发现需要从模板实例创建新实例时,ndarray子类的新实例也可以通过与View Cast非常相似的机制来实现。这最明显的地方是当您获取子类数组的切片时。例如:

>>>
>>> v = c_arr[1:]
>>> type(v) # the view is of type 'C'
<class 'C'>
>>> v is c_arr # but it's a new instance
False

切片是原始数据的视图c_arr。因此,当我们从ndarray进行查看时,我们将返回一个相同类的新ndarray,它指向原始数据。

在使用ndarray时,还有其他需要我们提供此类视图的要点,例如复制数组(c_arr.copy()),创建ufunc输出数组(有关ufuncs和其他函数请参见__array_wrap__)以及简化方法(如 c_arr.mean())。

视图转换和新模板的关系

这些路径都使用相同的机器。我们在这里有所不同,因为它们导致您的方法输入不同。具体来说, 视图转换意味着您已经从ndarray的任何潜在子类中创建了数组类型的新实例。 通过模板创建new 意味着您已经从现有实例创建了类的新实例,例如,允许您跨子类特有的属性进行复制。

子类化的含义

如果我们将ndarray子类化,则不仅需要处理数组类型的显式构造,还需要处理View铸造或 从template创建new。NumPy拥有执行此操作的机制,并且这种使子类化成为稍微不标准的机制。

ndarray用于支持子类中的视图和new-from-template的机制有两个方面。

首先是使用该ndarray.__new__方法进行对象初始化的主要工作,而不是使用更常用的__init__ 方法。第二个方法是使用该__array_finalize__方法允许子类在从模板创建视图和新实例之后进行清理。

在一个简短的Python底漆__new____init__

__new__是标准的Python方法,如果存在,则在__init__创建类实例之前被调用。有关更多详细信息,请参见python __new__文档

例如,考虑以下Python代码:

class C:
    def __new__(cls, *args):
        print('Cls in __new__:', cls)
        print('Args in __new__:', args)
        # The `object` type __new__ method takes a single argument.
        return object.__new__(cls)

    def __init__(self, *args):
        print('type(self) in __init__:', type(self))
        print('Args in __init__:', args)

意味着我们得到:

>>>
>>> c = C('hello')
Cls in __new__: <class 'C'>
Args in __new__: ('hello',)
type(self) in __init__: <class 'C'>
Args in __init__: ('hello',)

当我们调用时C('hello'),该__new__方法将其自身的类作为第一个参数,并将传递的参数作为字符串 'hello'。在python调用之后__new__,它通常(如下所示)调用我们的__init__方法,其输出__new__作为第一个参数(现在是一个类实例),然后是传递的参数。

如您所见,对象可以在__new__ 方法中或在__init__方法中或在这两者中初始化,实际上ndarray没有__init__方法,因为所有初始化都在__new__方法中完成。

为什么要使用__new__而不是仅仅使用普通的__init__?因为在某些情况下,对于ndarray,我们希望能够返回某个其他类的对象。考虑以下:

class D(C):
    def __new__(cls, *args):
        print('D cls is:', cls)
        print('D args in __new__:', args)
        return C.__new__(C, *args)

    def __init__(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kimboyang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值