According to the numpy/scipy doc on numpy.r_
here, it is "not a function, so takes no parameters".
If it is not a function, what is the proper term for "functions" such as numpy.r_
?
r_ = <numpy.lib.index_tricks.RClass object> Translates slice objects to concatenation along the first axis. This is a simple way to build up arrays quickly. There are two use cases. If the index expression contains comma separated arrays, then stack them along their first axis.
numpy. c_ = <numpy.lib.index_tricks.CClass object> Translates slice objects to concatenation along the second axis. This is short-hand for np. r_['-1,2,0', index expression] , which is useful because of its common occurrence.
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 ...
It's a class instance (aka an object):
In [2]: numpy.r_
Out[2]: <numpy.lib.index_tricks.RClass at 0x1923710>
A class is a construct which is used to define a distinct type - as such a class allows instances of itself. Each instance can have properties (member/instance variables and methods).
One of the methods a class can have is the __getitem__
method, this is called whenever you append [something,something...something]
to the name of the instance. In the case of the numpy.r_
instance the method returns a numpy array.
Take the following class for example:
class myClass(object)
def __getitem__(self,i)
return i*2
Look at these outputs for the above class:
In [1]: a = myClass()
In [2]: a[3]
Out[2]: 6
In [3]: a[3,4]
Out[3]: (3, 4, 3, 4)
I am calling the __getitem__
method of myClass (via the []
parentheses) and the __getitem__
method is returning (the contents of a list * 2 in this case)- it is not the class/instance behaving as a function - it is the __getitem__
function of the myClass
instance which is being called.
On a final note, you will notice that to instantiate myClass
I had to do a = myClass()
whereas to get an instance of RClass
you use numpy.r_
This is because numpy instantiates RClass
and binds it to the name numpy.r_ itself. This is the relevant line in the numpy source code. In my opinion this is rather ugly and confusing!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With