根据numpy/scipy关于 numpy.r_ 的文档(在此处),它“不是函数,因此不接受参数”。
如果它不是函数,那么像 numpy.r_ 这样的“函数”的正确术语是什么?
如果它不是函数,那么像 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))
< p > r_
对象“滥用”这个事实创建了一个“函数”,它接受切片符号,并执行一些附加操作,如将所有内容连接在一起并返回结果,以便您可以编写 x = np.r_[1:11, 15, 20:110:10]
。文档中的“不是函数,因此不接受参数”略有误导...< /p >
这是一个类的实例(也称为对象):
In [2]: numpy.r_
Out[2]: <numpy.lib.index_tricks.RClass at 0x1923710>
类是一个用于定义独特类型的构造体 - 因此,类允许其实例。每个实例都可以具有属性(成员/实例变量和方法)。
类可以拥有的方法之一是__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的结果。这不是类/实例像函数一样的行为,而是被调用的myClass
实例的__getitem__
函数。
最后需要注意的是,你会注意到要实例化myClass
,我必须执行a = myClass()
,而要获取RClass
的实例,则需使用numpy.r_
。这是因为NumPy实例化RClass
并将其绑定到名称numpy.r_
本身上。 在我看来,这相当丑陋和令人困惑! 这是NumPy源代码中相关的行。
RClass
的一个实例,而不是一个类本身。 - Robert Kern__getitem__
而不是 __call__
来利用切片符号。 - hpauljnumpy.r_
不会实例化一个RClass
,它是引用已经存在的一个实例。myr=type(np.r_)()
创建一个新的实例,具有新的ID。但我认为没有实际的理由这样做。 - hpaulj
__getitem__
方法和__call__
方法。np.array
,np.r_
和[]
具有前者,函数具有后者。 实际上,如果对象具有__call__
,则任何对象都可以被调用。 - hpaulj