В соответствии с numpy/scipy doc на numpy.r_
здесь, это "не функция, поэтому не принимает параметров".
Если это не функция, то каков правильный термин для "функций", таких как numpy.r_
?
В соответствии с numpy/scipy doc на numpy.r_
здесь, это "не функция, поэтому не принимает параметров".
Если это не функция, то каков правильный термин для "функций", таких как numpy.r_
?
Это экземпляр класса (он же объект):
In [2]: numpy.r_
Out[2]: <numpy.lib.index_tricks.RClass at 0x1923710>
Класс - это конструкция, которая используется для определения отдельного типа - так как такой класс допускает экземпляры самого себя. Каждый экземпляр может иметь свойства (переменные-члены/экземпляры и методы).
Одним из методов, которые может иметь класс, является метод __getitem__
, он вызывается всякий раз, когда вы добавляете [something,something...something]
к имени экземпляра. В случае экземпляра numpy.r_
метод возвращает пустой массив.
Возьмите следующий класс, например:
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)
Я вызываю метод __getitem__
myClass (через круглые скобки []
), и возвращается метод __getitem__
(в данном случае содержимое списка * 2) - это не поведение класса/экземпляра как функция - это функция __getitem__
экземпляра myClass
, которая вызывается.
В заключение отметим, что для создания экземпляра myClass
мне пришлось сделать a = myClass()
, тогда как для получения экземпляра RClass
вы используете numpy.r_
. Это потому, что numpy создает экземпляр RClass
и связывает его с именем numpy..r_ себя. Это соответствующая строка в простом исходном коде. На мой взгляд, это довольно уродливо и запутанно!
Я бы сказал, что для всех целей r_
- это функция, но реализованная умным взломом с использованием другого синтаксиса. Майк уже объяснил, что 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__
объекта, где запись двоеточия преобразуется в фрагмент объекта:
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]
. "Не функция, поэтому не принимает параметров" в документации немного вводит в заблуждение...