I would argue that for all purposes r_
is a function, but one implemented by a clever hack using different syntax. Mike already explained how r_
is in reality not a function, but a class instance of RClass
, which has __getitem__
implemented, so that you can use it as r_[1]
. The cosmetic difference is that you use square brackets instead of curved ones, so you are not doing a function call, but you are actually indexing the object. Although this is technically true, for all purposes, it works just like a function call, but one that allows some extra syntax not allowed by a normal function.
The motivation for creating r_
probably comes from Matlab's syntax, which allows to construct arrays in a very compact way, like x = [1:10, 15, 20:10:100]
. To achieve the same in numpy, you would have to do x = np.hstack((np.arange(1,11), 15, np.arange(20,110,10)))
. Using colons to create ranges is not allowed in python, but they do exist in the form of the slice notation to index into a list, like L[3:5]
, and even A[2:10, 20:30]
for multi-dimensional arrays. Under the hood, these index notation gets transformed to a call to the __getitem__
method of the object, where the colon notation gets transformed into a slice object:
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))
The r_
object 'abuses' this fact to create a 'function' that accepts slice notation, which also does some additional things like concatenating everything together and returning the result, so that you can write x = np.r_[1:11, 15, 20:110:10]
. The "Not a function, so takes no parameters" in the documentation is slightly misleading ...
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…