Подтвердить что ты не робот

Numpy.r_ не является функцией. Что это?

В соответствии с numpy/scipy doc на numpy.r_ здесь, это "не функция, поэтому не принимает параметров".

Если это не функция, то каков правильный термин для "функций", таких как numpy.r_?

4b9b3361

Ответ 1

Это экземпляр класса (он же объект):

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_ себя. Это соответствующая строка в простом исходном коде. На мой взгляд, это довольно уродливо и запутанно!

Ответ 2

Я бы сказал, что для всех целей 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]. "Не функция, поэтому не принимает параметров" в документации немного вводит в заблуждение...