Ответ 1
Любой класс Python может быть создан так, чтобы его экземпляры принимали одну или обе нотации: он будет принимать парс, реализуя функцию с именем __call__
и скобки, реализуя __getitem__
.
np.r_
имеет класс, который реализует __getitem__
, чтобы делать более интересные вещи, чем обычно. То есть класс r_
(называемый np.lib.index_tricks.RClass
) делает что-то вроде этого:
class RClass:
def __getitem__(self, item):
# r_ fancyness
Вероятно, это было сделано для того, чтобы он мог использовать нотацию среза - например, когда у вас есть список (или np-массив или любой другой объект, реализующий этот протокол) l
, и вы делаете:
l[:5]
Python автоматически создает объект slice
для перехода к __getitem__
.
Этот синтаксис не работает с __call__
- пользователю нужно будет создать срез явно, выполнив l(slice(5))
.
Обратите внимание, что __call__
может принимать любые аргументы; в то время как __getitem__
всегда принимает ровно один аргумент: когда вы делаете что-то вроде my_array[1:3, 2:5]
, Python проходит в одном кортеже фрагментов. Но, как вы видите, с r_
, содержимое не ограничивается числами и срезами - подобно любой другой функции, Python будет счастливо проходить в любом объекте и оставить его классу для разработки того, что он означает.