Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Lambdify与Python一起工作,但与Cython一起引发异常_Python_Optimization_Cython_Sympy_Lambdify - Fatal编程技术网

Lambdify与Python一起工作,但与Cython一起引发异常

Lambdify与Python一起工作,但与Cython一起引发异常,python,optimization,cython,sympy,lambdify,Python,Optimization,Cython,Sympy,Lambdify,我的网站运行这个Python脚本,如果使用Cython,这个脚本将更加优化。最近我需要补充一点,Cython的情况不太好 所以我把这个问题简化成一个最简单的例子。在代码中,我有一个带有字符串键的字典,其中的值是列表。我想使用这些键作为变量。在下面的简化示例中,只有1个变量,但通常我需要更多。请检查以下示例: import numpy as np from sympy.parsing.sympy_parser import parse_expr from sympy.utilities.lambd

我的网站运行这个Python脚本,如果使用Cython,这个脚本将更加优化。最近我需要补充一点,Cython的情况不太好

所以我把这个问题简化成一个最简单的例子。在代码中,我有一个带有字符串键的字典,其中的值是列表。我想使用这些键作为变量。在下面的简化示例中,只有1个变量,但通常我需要更多。请检查以下示例:

import numpy as np
from sympy.parsing.sympy_parser import parse_expr
from sympy.utilities.lambdify import lambdify, implemented_function
from sympy import S, Symbol
from sympy.utilities.autowrap import ufuncify


def CreateMagneticFieldsList(dataToSave,equationString,DSList):

    expression  = S(equationString)
    numOfElements = len(dataToSave["MagneticFields"])

    #initialize the magnetic field output array
    magFieldsArray    = np.empty(numOfElements)
    magFieldsArray[:] = np.NaN

    lam_f = lambdify(tuple(DSList),expression,modules='numpy')
    try:
        # pass
        for i in range(numOfElements):
            replacementList = np.zeros(len(DSList))


            for j in range(len(DSList)):
                replacementList[j] = dataToSave[DSList[j]][i]

            try:
                val = np.double(lam_f(*replacementList))

            except:
                val = np.nan
            magFieldsArray[i] = val
    except:
        print("Error while evaluating the magnetic field expression")
    return magFieldsArray


list={"MagneticFields":[1,2,3,4,5]}

out=CreateMagneticFieldsList(list,"MagneticFields*5.1",["MagneticFields"])

print(out)
让我们称之为
test.py
。这很有效。现在我想对此进行cythonize,因此我使用以下脚本:

#!/bin/bash

cython --embed -o test.c test.py
gcc -pthread -fPIC -fwrapv -Ofast -Wall -L/lib/x86_64-linux-gnu/ -lpython3.4m -I/usr/include/python3.4 -o test.exe test.c
现在,如果我执行
/test.exe
,它会抛出一个异常!例外情况如下:

Traceback (most recent call last):
  File "test.py", line 42, in init test (test.c:1811)
    out=CreateMagneticFieldsList(list,"MagneticFields*5.1",["MagneticFields"])
  File "test.py", line 19, in test.CreateMagneticFieldsList (test.c:1036)
    lam_f = lambdify(tuple(DSList),expression,modules='numpy')
  File "/usr/local/lib/python3.4/dist-packages/sympy/utilities/lambdify.py", line 363, in lambdify
    callers_local_vars = inspect.currentframe().f_back.f_locals.items()
AttributeError: 'NoneType' object has no attribute 'f_locals'
所以问题是:我怎样才能让兰比菲与赛顿合作

注意:我想指出我有Debian Jessie,这就是我使用Python 3.4的原因。另外,我想指出,当我不使用
lambdify
时,我对Cython没有任何问题。我还想指出,Cython已通过
pip3安装Cython更新到最新版本--升级

中有说明

堆叠框架

目前,作为异常的一部分,我们生成假回溯 传播,但不要填写局部变量,也不能填写co_代码。成为 完全兼容,我们必须生成这些堆栈帧对象 在函数调用时(具有潜在的性能损失)。我们可以 有一个选项可以启用此选项进行调试

f_locals
in

AttributeError: 'NoneType' object has no attribute 'f_locals'

似乎指向了这个不兼容问题。

这是一个解决实际问题的方法(在注释和@jhakala的回答中确定),Cython没有为编译函数生成完整的回溯/内省信息。我从您的评论中得知,出于速度原因,您希望使用Cython编译大部分程序

“解决方案”是只对需要调用
lambdify
的单个函数使用Python解释器,而将其余函数保留在Cython中。您可以使用
exec
执行此操作

这个想法的一个非常简单的例子是

exec("""
def f(func_to_call):
    return func_to_call()""")

# a Cython compiled version    
def f2(func_to_call):
    return func_to_call())
可以将其编译为Cython模块并导入,导入后Python解释器将运行字符串中的代码,并正确地将
f
添加到模块全局。如果我们创建一个纯Python函数

def g():
    return inspect.currentframe().f_back.f_locals
调用
cython\u module.f(g)
会给我一个带有键
func\u to\u call
(如预期)的字典,而
cython\u module.f2(g)
会给我
\u main\u
模块全局(但这是因为我是从解释器运行的,而不是使用
--embed


编辑:基于代码的完整示例

from sympy import S, lambdify # I'm assuming "S" comes from sympy
import numpy as np

CreateMagneticFieldsList = None # stops a compile error about CreateMagneticFieldsList being undefined

exec("""def CreateMagneticFieldsList(dataToSave,equationString,DSList):

    expression  = S(equationString)
    numOfElements = len(dataToSave["MagneticFields"])

    #initialize the magnetic field output array
    magFieldsArray    = np.empty(numOfElements)
    magFieldsArray[:] = np.NaN

    lam_f = lambdify(tuple(DSList),expression,modules='numpy')
    try:
        # pass
        for i in range(numOfElements):
            replacementList = np.zeros(len(DSList))


            for j in range(len(DSList)):
                replacementList[j] = dataToSave[DSList[j]][i]

            try:
                val = np.double(lam_f(*replacementList))

            except:
                val = np.nan
            magFieldsArray[i] = val
    except:
        print("Error while evaluating the magnetic field expression")
    return magFieldsArray""")


list={"MagneticFields":[1,2,3,4,5]}

out=CreateMagneticFieldsList(list,"MagneticFields*5.1",["MagneticFields"])
print(out)
当使用脚本编译时,将打印此文件

[5.1 10.2 15.3 20.4 25.5]


实际上,我所做的只是将函数包装在一个
exec
语句中,因此它由Python解释器执行。这部分不会从Cython中看到任何好处,但是程序的其余部分仍然会看到。如果你想最大限度地利用Cython编译,你可以把它分成多个函数,这样只有包含
lambdify
的一小部分在
exec

中相关:从我看来,
--embed
不是魔法,也不会进行优化(它只是从
libpython
调用解释器),所以没什么必要这么做。目的是什么?@ivan_pozdeev嗯,它比原始蟒蛇快多了。。。您是否建议删除
--embed
?可能相关,“目前,作为异常传播的一部分,我们生成假回溯,但不要填写局部变量,也不能填写co_代码。”@J.J.Hakala将此作为一个答案发布,因为很可能是这样。您可以修改您的代码以与我提供的参数兼容吗?我对这个很陌生。我试着把这些作为参数放到
f
中,但我得到了一个错误:
fdata=f(CreateMagneticFieldList,all_data,feqStr,all_symbols)TypeError:“\u io.TextIOWrapper”对象不可调用
Ah。我想你有点误解了。您需要在
eval
内部定义
createMagneticFieldList
,因为它是调用
lambdify
的。我只是举了一个非常简单的例子来说明这个想法是有效的<正如我定义的那样,code>f
真的毫无意义。(如果这仍然让人困惑的话,我会尽量使我的代码更加完整)。我非常非常感谢一个实用的例子,最好是基于我在问题中提供的例子!我也向你保证,每个人都会喜欢它,因为这个问题很常见,没有人找到解决办法。