2014-11-07 1 views
1

Я хочу сделать следующее: Я хочу определить рекурсивную функцию funct, в которой последняя ссылка сама возвращает номер массива temp. Проблема в том, что funct должен выполнять интеграл от себя (см. Код ниже), и это было бы очень легко, если funct мог принять двоеточие : в качестве аргумента. Итак, у меня есть это (упрощенный) код до сих пор:Как функция может принимать двоеточие (оператор диапазона) в качестве аргумента (в Python)?

import numpy as np 
import scipy.integrate as ints 

temp = np.array([[1,2,3,4,5],[4,0,6,7,8],[7,8,9,10,11],[1,2,3,4,5],[6,7,8,9,10]]) 

def funct(x,y,n): 
    if n>1: 
     return (temp[x,y] + ints.cumtrapz(temp[x,:]*funct(:,y,n-1), x=None, dx=1, initial=0)[-1]) 
    else: 
     return temp[x,y] 
funct = np.vectorize(funct) 
funct(1,1,3) 

Проблема заключается в том, что funct не может принять двоеточие : в качестве аргумента, это не имеет значения, если я хочу Vectorize к funct позже код.

Например, если я изменю эту часть кода выше

ints.cumtrapz(temp[x,:]*funct(:,y,n-1), x=None, dx=1, initial=0)[-1]) 

для

ints.cumtrapz(temp[x,:]*temp[:,y], x=None, dx=1, initial=0)[-1]) 

У меня нет никаких проблем. Я просто хочу сделать последнюю часть рекурсивно.

+0

Двоеточие не является оператором диапазона для Python или '' 'ndarray'''. Что dp ypu хочет передать в качестве аргумента? – wwii

ответ

2

Во-первых, у Python нет «операторов дальности», как некоторые другие языки. : генерирует slice s, которые совершенно отличаются от range. И, что более важно, синтаксис : является частью синтаксиса slicing (так называемый расширенный индексирование или расширенная подписка), он не стоит сам по себе.

Таким образом, простой способ, чтобы написать свой код, чтобы использовать slice буквальным:

Конечно, вы могли бы также избежать всего этого беспорядка и использовать только явный срез буквального:

def funct(x, y, n): 
    if n>1: 
     return (temp[x,y] + ints.cumtrapz(temp[x,:]*funct(slice(None),y,n-1), x=None, dx=1, initial=0)[-1]) 
    else: 
     return temp[x,y] 

Итак, почему нет синтаксиса для «литералов среза», что более удобно, чем вызов конструктора slice? Потому что никто не придумал убедительный аргумент, выработанное потенциальные неясности синтаксиса, и представлен патч. *

* Обратите внимание, что Python сделал добавить синтаксис для многоточия литералов на их own- ... является буквальной для Ellipsis, одноэлементное значение типа ellipsis. Многие хотели этого, не было никаких двусмысленностей, кроме кода, который был уже незаконным, кто-то написал патч, и это было принято с небольшой суетой.


Хотя синтаксис для расширенной индексации и синтаксис для вызовов функции несколько похожи, они не идентичны. Это означает, что вы не можете использовать вызовы функций как, например, язык, специфичный для домена, для обертывания отложенной нарезки.

Одна вещь, вы может сделать, это создать тип ломтика-обертку, чтобы с помощью самих нарезая выражения в качестве такого предметно-ориентированного языка:

class Slicer: 
    def __getitem__(self, idx): 
     return idx 
s = Slicer() 

Теперь s[:] является конструктором для slice(None) и s[3:23:2, ..., 4] является конструктор для (slice(3, 23, 2), Ellipsis, 4). Таким образом, вы можете написать что-то вроде этого:

funct(s[:,y,n-1]) 

Ваш funct класс получит кортеж slice объектов и целых чисел, которые можно впоследствии использовать для индексирования массива, вызвав его __getitem__ непосредственно.

И вы можете обернуть больше этого, если хотите. Например:

class SliceCallable(object): 
    def __init__(self, f): 
     self.f = f 
    def __getitem__(self, idx): 
     if isinstance(idx, collections.abc.Sequence): 
      return self.f(*idx) 
     else: 
      return self.f(idx) 
    def __call__(self, *args): 
     return self.f(*args) 

@SliceCallable 
def funct(x, y, n): 
    if n>1: 
     return (temp[x,y] + ints.cumtrapz(temp[x,:]*funct[:,y,n-1], x=None, dx=1, initial=0)[-1]) 
    else: 
     return temp[x,y] 

Теперь funct можно назвать либо funct(1, 2, 3) или funct[1, 2, 3] -or как funct[:, 2, 3] или funct[4:-1]. Это означает, что x будет slice(None, None, None) или slice(4, -1, None). И вы можете использовать это в выражении индексации; temp[slice(None, None), 3] может выглядеть не так хорошо, как temp[:, 3], но это означает то же самое.

+0

Спасибо @abarnet !!. Это просто информация, которую я искал .. !!! – Jorge

+0

Примечание для конкретного использования 'numpy', вы можете использовать, например. 'np.s_ [4: 6]', чтобы вернуть объект 'slice'. См. Https://docs.scipy.org/doc/numpy/reference/generated/numpy.s_.html. – klimaat

Смежные вопросы