推迟在语法上执行函数

时间:2018-05-16 09:16:54

标签: python numpy generator decorator

我有一个用python编写的相当广泛的模拟工具,它要求用户调用函数以严格的顺序设置环境,因为np.ndarrays最初是创建的(并且由附加等)然后定义对这些阵列的特定单元的存储器视图 目前,环境的每个部分都需要设置大约4个不同的函数调用,并且容易>> 100个部分 因此,我需要通过语法(不基于计时器)将每个部分的函数调用结合起来,推迟执行某些函数,直到所有前面的函数都被执行,同时仍保持严格的顺序以便能够使用内存视图。

此外,用户调用的所有函数都使用PEP 3102样式的仅关键字参数来减少输入错误的概率所有实例方法使用self作为第一个参数,self包含对数组的引用以构造内存视图。

我当前的实现是使用list来存储函数,并使用dict来为每个函数的keyworded参数。这里显示了这一点,省略了类和自身参数,使其变短:

def fun1(*, x, y):  # easy minimal example function 1
    print(x * y)
def fun2(*, x, y, z):  # easy minimal example function 2
    print((x + y) / z)

fun_list = []  # list to store the functions and kwargs
fun_list.append([fun1, {'x': 3.4, 'y': 7.0}])  # add functions and kwargs
fun_list.append([fun2, {'x':1., 'y':12.8, 'z': np.pi}])
fun_list.append([fun2, {'x':0.3, 'y':2.4, 'z': 1.}])

for fun in fun_list:
    fun[0](**fun[1])

我想要实现的是使用decorator通过添加generator推迟函数执行,以便能够在调用函数时将所有参数传递给函数,但不执行他们,如下图所示:

def postpone(myfun):  # define generator decorator
    def inner_fun(*args, **kwargs):
        yield myfun(*args, **kwargs)
    return inner_fun

fun_list_dec = []  # list to store the decorated functions
fun_list_dec.append(postpone(fun1)(x=3.4, y=7.0))  # add decorated functions
fun_list_dec.append(postpone(fun2)(x=1., y=12.8, z=np.pi))
fun_list_dec.append(postpone(fun2)(x=0.3, y=2.4, z=1.))

for fun in fun_list_dec:  # execute functions
    next(fun)

哪种方法最好(最pythonic)?有什么缺点吗?
最重要的是:np.ndarraysself内部函数的引用是否仍然是引用,这样在执行函数时这些数组的内存地址仍然正确, if 内存地址在之间更改将函数调用保存到列表(或正在修饰)并执行它们?
执行速度无关紧要。

2 个答案:

答案 0 :(得分:3)

< p>在这里使用生成器没有多大意义。您基本上模拟部分应用程序。因此,这似乎是< code> functools.partial< / code>的用例。既然你坚持使用只有关键字的参数,那么这将很好用:< / p> < pre>< code>在[1]中:def fun1(*,x,y):#easy minimal example function 1    ...:print(x * y)    ...:def fun2(*,x,y,z):#easy minimal example function 2    ...:print((x + y)/ z)    ...: 在[2]中:从functools导入部分 在[3]中:fun_list = [] 在[4]中:fun_list.append(partial(fun1,x = 3.4,y = 7.0)) 在[5]中:fun_list.append(partial(fun2,x = 1。,y = 12.8,z = 3.14)) 在[6]中:fun_list.append(partial(fun2,x = 0.3,y = 2.4,z = 1。)) 在[7]中:对于fun_list中的f:    ...: F()    ...: 23.8 4.3949044585987265 2.6999999999999997 < /代码>< /预> < p>你没有< em>有< / em>使用< code> functools.partial< / code>或者,你可以“手动”进行部分申请,只是为了证明:< / p> < pre>< code>在[8]中:fun_list.append(lambda:fun1(x = 5.4,y = 8.7)) 在[9]中:fun_list [-1]() 46.98 < /代码>< /预>

答案 1 :(得分:0)

由于评论代码太复杂而且基于juanpa.arrivillaga的答案,我将添加一篇完整的帖子,简短解释我的意思是更新对数组的引用:

def fun1(*, x, y):  # easy minimal example function 1
    print(x * y)

arr = np.random.rand(5)
f1_lam = lambda:fun1(x=arr, y=5.)
f1_par = partial(fun1, x=arr, y=5.)
f1_lam()  # Out[01]: [0.55561103 0.9962626  3.60992174 2.55491852 3.9402079 ]
f1_par()  # Out[02]: [0.55561103 0.9962626  3.60992174 2.55491852 3.9402079 ]

# manipulate array so that the memory address changes and
# passing as reference is "complicated":
arr = np.append(arr, np.ones((2,1)))
f1_lam()  # Out[03]: [0.55561103 0.9962626  3.60992174 2.55491852 3.9402079  5. 5.]
f1_par()  # Out[02]: [0.55561103 0.9962626  3.60992174 2.55491852 3.9402079 ]

lambda的行为正是我在这个问题中寻找的行为。

dictdecorator的示例不起作用,functools.partial也不行。知道为什么lambda有效吗?只是出于兴趣:有没有办法更新dict中对数组的引用,以便它也可以这样工作?