【发布时间】:2013-09-03 20:34:19
【问题描述】:
根据numpy.r_here 上的 numpy/scipy 文档,它“不是函数,因此不带参数”。
如果不是函数,那么numpy.r_等“函数”的专有名词是什么?
【问题讨论】:
根据numpy.r_here 上的 numpy/scipy 文档,它“不是函数,因此不带参数”。
如果不是函数,那么numpy.r_等“函数”的专有名词是什么?
【问题讨论】:
我认为r_是一个函数,但它是由一个聪明的黑客使用不同的语法实现的。 Mike 已经解释了r_ 实际上不是一个函数,而是RClass 的一个类实例,它实现了__getitem__,因此您可以将它用作r_[1]。外观上的区别在于您使用方括号而不是弯曲的括号,因此您不是在进行函数调用,而是实际上是在索引对象。虽然这在技术上是正确的,但对于所有目的来说,它就像函数调用一样工作,但它允许一些普通函数不允许的额外语法。
创建r_ 的动机可能来自Matlab 的语法,它允许以非常紧凑的方式构造数组,例如x = [1:10, 15, 20:10:100]。要在 numpy 中达到同样的效果,您必须执行 x = np.hstack((np.arange(1,11), 15, np.arange(20,110,10)))。 python 中不允许使用冒号创建范围,但它们确实以切片表示法的形式存在以索引到列表中,例如L[3:5],甚至A[2:10, 20:30] 用于多维数组。在后台,这些索引符号被转换为对对象的 __getitem__ 方法的调用,其中冒号符号被转换为 slice 对象:
In [13]: class C(object):
...: def __getitem__(self, x):
...: print x
In [14]: c = C()
In [15]: c[1:11, 15, 20:110:10]
(slice(1, 11, None), 15, slice(20, 110, 10))
r_ 对象“滥用”这一事实来创建一个接受切片表示法的“函数”,该函数还执行一些附加操作,例如将所有内容连接在一起并返回结果,以便您可以编写 x = np.r_[1:11, 15, 20:110:10]。文档中的“不是函数,所以不带参数”有点误导......
【讨论】:
__getitem__ 方法和__call__ 方法。 np.array、np.r_ 和 [] 有前者,函数有后者。事实上,任何有__call__的对象都是可调用的。
这是一个类实例(又名对象):
In [2]: numpy.r_
Out[2]: <numpy.lib.index_tricks.RClass at 0x1923710>
类是一种构造,用于定义不同的类型 - 因为这样的类允许instances 自身。每个实例都可以有属性(成员/实例变量和方法)。
类可以拥有的方法之一是__getitem__ 方法,每当您将[something,something...something] 附加到实例的名称时都会调用此方法。对于 numpy.r_ 实例,该方法返回一个 numpy 数组。
以下面的类为例:
class myClass(object)
def __getitem__(self,i)
return i*2
查看上述类的这些输出:
In [1]: a = myClass()
In [2]: a[3]
Out[2]: 6
In [3]: a[3,4]
Out[3]: (3, 4, 3, 4)
我正在调用 myClass 的 __getitem__ 方法(通过 [] 括号)并且 __getitem__ 方法正在返回(在这种情况下是列表的内容 * 2)- 不是 em> 类/实例表现为函数 - 它是被调用的 myClass 实例的 __getitem__ 函数。
最后一点,您会注意到要实例化 myClass 我必须执行 a = myClass() 而要获得 RClass 的实例您使用 numpy.r_ 这是因为 numpy 实例化 RClass 并将其绑定到名称 numpy.r_ 本身。 This is the relevant line in the numpy source code。在我看来,这相当丑陋和令人困惑!
【讨论】:
RClass 的一个实例,而不是一个类本身。
__getitem__ 代替__call__ 以利用slice 表示法。