我想执行以下操作:我想定义一个递归函数funct,其中其自身的最后一个引用返回一个数组temp的数字。问题在于funct必须对其自身进行积分(请参见下面的代码),如果funct可以接受冒号:作为参数,这将非常容易。因此,到目前为止,我有以下(简化的)代码:

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不能接受冒号:作为参数,如果稍后我想在代码中将其矢量化为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])


我没问题我只想递归地做最后一部分。

最佳答案

首先,Python没有像其他语言那样具有“范围运算符”。 :生成slice,这是与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确实为其本身添加了省略号文字的语法-...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]funct[:, 2, 3]funct[4:-1]。这仅表示x将是slice(None, None, None)slice(4, -1, None)。您可以在索引表达式中使用它; temp[slice(None, None), 3]可能不如temp[:, 3]好看,但这意味着同一件事。

关于python - 函数如何接受冒号(范围运算符)作为参数(在Python中)?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26811712/

10-10 04:14