调用在C中创建文件的python函数

时间:2019-04-25 15:57:01

标签: python c

我有一个创建文件的简单python函数:

kmer_counter.py

def counter(k):

  list_kmer = []
  freq = {}

  reader = open("out/clean_read.txt", 'r')

  while True:
    line = reader.readline().rstrip()

    if not line:
      break

    for i in range(0, len(line) - k + 1):
      kmer = line[i : i + k]

      if kmer in freq:
        freq[kmer] += 1
      else:
        freq[kmer] = 1

  reader.close()

  freq = {key:val for key, val in freq.items() if val != 1}

  writer = open("out/kmer.txt", 'w')

  for key in freq.keys():
    writer.write(key + '\n')

  writer.close()

我尝试使用Python.h头文件在C程序中调用它们。我没有任何类型的错误,但是在主文件末尾,未创建文件。 这是main.c文件:

#include <stdio.h>
#include <stdlib.h>

#if defined(__APPLE__) || defined(__MACH__)
    #include <Python/Python.h>
#elif defined(unix) || defined(__unix__) || defined(__unix)
    #include <Python.h>
    #include <stdint.h>
#endif

int main(void) {
    Py_SetProgramName(argv[0]);
    Py_Initialize();

    PyObject* myModuleString = PyUnicode_FromString((char *) "kmer_counter");
    PyObject* myModule = PyImport_Import(myModuleString);
    PyObject* myFunction = PyObject_GetAttrString(myModule,(char *) "counter");

    PyObject* args = PyUnicode_FromString("5");
    PyObject *myResult = PyObject_CallFunctionObjArgs(myFunction, args);

    Py_Finalize();
}

对于编译文件,我使用标志-I/usr/include/python2.7 -lpython2.7

我对此说法有不同的疑问,但我没有找到解决该问题的正确方法。

这是文件clean_read.txt的内容:

ACCAG
CCAGTG
GTGAAC
CAGTGA
ACCAGT
TGAACG
GAACGGTA
CAGTGTA
AACGGTA
GAACGG
AGTGAACG
AACGGT
CAGTGAA
TGAACGGTA

编辑

我在PyObject_CallFunctionObjArgs之后添加了以下代码行,但是它什么也没打印出来。

if (myResult) { 
  fputs("result: ", stderr); 
  PyObject_Print(myResult, stderr, 0); 
  putc('\n', stderr); 
}
else { 
    fputs("exception:\n", stderr);
    PyErr_PrintEx(0);
}

strace在此link输出

将我的主要代码替换为第一个答案中的代码后,这是输出:

This is the report what it outputs:
main begins
Py_SetProgramName: ok
Py_Initialize: ok
PyUnicode_FromString('kmer_counter'): result: r
u'kmer_counter'
PyImport_Import(myModuleString): exception:
ImportError: No module named kmer_counter

2 个答案:

答案 0 :(得分:2)

您的代码中至少有两个严重错误,也许还有更多。您需要检查所有正在调用的函数的返回值,否则会错过它们。

两个最明显的问题是:

  1. 您没有通过NULL要求的PyObject_CallFunctionObjArgs标记;该调用必须传递NULL的最终参数,以用作指示可变长度参数列表结束位置的标记。 PyObject *myResult = PyObject_CallFunctionObjArgs(myFunction, args);应该是PyObject *myResult = PyObject_CallFunctionObjArgs(myFunction, args, NULL);
  2. 您的函数需要一个单独的参数k,该参数的使用方式显然希望它是Python int,但是您正在显式构造Python str ;到达for i in range(0, len(line) - k + 1):的那一刻,它将立即引发TypeErrorPyObject* args = PyUnicode_FromString("5");应该为PyObject* args = PyLong_FromLong(5);,以产生正确的类型。

在两种情况下,错误都发生在您未检查返回码的最终调用上;类型问题会绕过Python函数的其余部分而引发Python级异常,而varargs错误可能会导致无法预料的可怕事情。您需要更加严格地检查返回值,并且需要更加注意API要求。

旁注:在这种情况下,您可以使用PyObject_CallFunction来替换相当数量的代码,包括所有不良代码,从而节省一些精力。所有这些:

PyObject* args = PyUnicode_FromString("5");
PyObject *myResult = PyObject_CallFunctionObjArgs(myFunction, args);

可以替换为:

PyObject *myResult = PyObject_CallFunction(myFunction, "i", 5);

这简化了工作(并减少了一个对象泄漏的对象的数量)。


更新为地址编辑:

看起来kmer_counter.py既不在您的工作目录中,也不在sys.path中的其他地方。如果从命令行运行,则最简单的解决方案是在运行可执行文件之前,cd进入与kmer_counter.py相同的目录(不必位于同一目录中)。另一个(有点怪异)的解决方案是创建/扩展PYTHONPATH环境变量,以包含包含kmer_counter.py的路径,例如在bash中,您可以这样做(遵循your comment的路径):

PYTHONPATH=./src/prepros ./app

或作为两行(其中export仅需要运行一次):

export PYTHONPATH=./src/prepros
./app

无论如何,只是为了让您了解正在执行的不必要工作量,这是将您的C代码简化为使用尽可能少的API调用(尽管使用zwol's check_PyAPI可以简化错误检查在实际代码中,您可能要通过立即死亡并显示错误消息的方式来处理一些错误):

int main(void) {
    Py_SetProgramName(argv[0]);
    Py_Initialize();

    // Load module without needing to construct PyUnicode manually
    PyObject* myModule = PyImport_ImportModule("kmer_counter");
    check_PyAPI("PyImport_ImportModule(\"kmer_counter\")", myModule);

    // Call function on module without needing to construct PyUnicode
    // or PyLong, and without needing to load the function itself
    PyObject* myResult = PyObject_CallMethod(myModule, "counter", "i", 5);
    Py_DECREF(myModule);  // Done with module, release reference
    check_PyAPI("PyObject_CallMethod(myModule, \"counter\", \"i\", 5)", myResult);

    // Do whatever you want with successful result

    Py_DECREF(myResult); // Done with result, release reference

    Py_Finalize();
}

完成您在两个呼叫中进行的所有五个呼叫的工作(我还添加了Py_DECREF来监视您的引用计数);当然,如果需要重新使用各种临时对象,那么有必要将它们临时化并反复使用它们,而不是让更高级别的函数一次又一次地重建PyUnicode或继续在其中重新查找该函数。题。但是,当您刚入门时,请让Python为您做更多的工作。稍后进行优化(由于避免了字节码解释器的开销,您已经比Python级别的代码更快)。

答案 1 :(得分:1)

ShadowRanger的回答就目前而言是正确的,但是您的UIScreen输出表明您的程序从未尝试打开任何名为if UIScreen.screens.count > 1 { let externalScreen = UIScreen.screens[1] print("Playing: externalScreen.bounds: \(externalScreen.bounds)") let secondWindow = UIWindow(frame: externalScreen.bounds) secondWindow.screen = externalScreen let overlayImage = UIImage(named: "rain.png") let overlayImageView = UIImageView(frame: externalScreen.bounds) overlayImageView.image = overlayImage secondWindow.addSubview(overlayImageView) secondWindow.isHidden = false secondWindow.makeKeyAndVisible() } 的文件,这意味着问题发生的时间更早,甚至可能在{ {1}}。现在是时候应用一种更具攻击性的调试技术了:在strace中记录每一个操作的结果。请用此代码替换整个测试程序,构建并运行它,并报告其输出。

kmer_counter.py