【问题标题】:Why does my 'hello world' Python C module work correctly in everything but IDLE?为什么我的“hello world”Python C 模块在除 IDLE 之外的所有内容中都能正常工作?
【发布时间】:2010-03-10 20:26:10
【问题描述】:

我为 Python 编译了一个简单的 hello world C 模块,它在我尝试过的所有东西中都能正常工作,但 IDLE 除外。这是我输入的内容来测试它:

>>> import hello
>>> hello.say_hello('Justin')

我已经从命令提示符(我使用的是 Windows)、Eclipse 的 PyDev 和 PieDream 中使用 Python 进行了尝试,它们都打印出 Hello Justin!。然而,在 IDLE 中它不打印任何东西——它只是给了我提示。

我使用的模块和setup.py来自this page。我认为问题出在编译器上。我正在使用 MinGW,它在 .cfg 文件中设置为 distutils 的编译器。我从命令提示符构建模块:

python setup.py build

得到

running build
running build_ext
building 'hello' extension
creating build
creating build\temp.win32-2.6
creating build\temp.win32-2.6\Release
C:\MinGW\bin\gcc.exe -mno-cygwin -mdll -O -Wall -IC:\Python26\include -IC:\Python26\PC -c hellomodule.c -o build\temp.win32-2.6\Release\hellomodule.o
writing build\temp.win32-2.6\Release\hello.def
creating build\lib.win32-2.6
C:\MinGW\bin\gcc.exe -mno-cygwin -shared -s build\temp.win32-2.6\Release\hellomodule.o build\temp.win32-2.6\Release\hello.def -LC:\Python26\libs -LC:Python26\PCbuild -lpython26 -lmsvcr90 -o build\lib.win32-2.6\hello.pyd

我认为这可能与其中的 -mno-cygwin 部分有关,但我不确定。

关于为什么这个模块不能在 IDLE 中工作的任何想法或建议?我应该使用不同的编译器吗?

【问题讨论】:

  • 这只是一个猜测,但您不应该在 Windows 中为 Python 使用 MSVC++ 吗?
  • @javier 您应该能够使用几乎任何 c 编译器。作为旁注,我在 linux 中使用 gcc 进行了教程,并且 idle 做了同样的事情:没有输出,但是 cmd 行有效,等等。好吧,我只是注意到这一点:如果你从命令行运行 idle 并运行脚本,输出被转储到终端窗口中。
  • @Javier 我也尝试过使用 distutils 和 MSVC++ 并得到相同的结果。

标签: python c windows module mingw


【解决方案1】:

听起来你好是直接写信给stdout。 Python的stdout不一定和C的stdout是同一个地方

通常您会向 Python 返回一个字符串,以便 Python 可以将其打印到它自己的 stdout

【讨论】:

  • 是的,我认为你是对的。如果我import syssys.stdout 在 IDLE 中与我运行模块的其他地方不同。 IDLE 将 sys.stdout 设置为来自 idlelib 模块的内容。
  • @Justin,现在看看是否可以将 C 字符串转换为 Python str 并返回:)
  • 小菜一碟。步步高升!奇怪的是,我见过的大多数示例都使用 printf,而显然返回字符串更合适。
【解决方案2】:

如果您需要从 C 编码扩展写入 Python 的 sys.stdout,您可以使用类似:

void writeout(const char* nullterminated)
{
    PyObject* sysmod = PyImport_ImportModuleNoBlock("sys");
    PyObject* pystdout = PyObject_GetAttrString(sysmod, "stdout");
    PyObject* result = PyObject_CallMethod(pystdout, "write", "s", nullterminated);
    Py_XDECREF(result);
    Py_XDECREF(pystdout);
    Py_XDECREF(sysmod);    
 }

(另外,大概还有一点错误检查——只是为了理智,以防有人做了一些疯狂的事情,比如del sys.stdout &c;-)。

当然,如果您需要多次写入,那么只获取一次stdout 可能会更有效,只要需要就保留它,并在完成“打印”内容时只删除一次(但那在您的 Python 调用者重新分配 sys.stdout 而您持有对其先前版本的引用的情况下,将不会表现得非常正确:您将继续打印到先前版本,就像行为相似的 Python 编码模块一样) .这种重复查找等同于在 Python 中执行 sys.stdout.write(somestring),它也每次都查找内容——速度稍慢但“语义上更安全”,以防您的 Python 调用者使用 sys.stdout 做“非常前卫”的事情(如您已经发现 IDLE 确实如此;-)。 ((不是那么前卫,真的,所以你可能想要适当地支持它;-))。

【讨论】:

  • 我已将代码修改为实际为我编译的代码,但仍然给你 +1,因为你让我朝着我必须做的正确方向前进。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-25
  • 1970-01-01
  • 1970-01-01
  • 2021-09-24
  • 2013-12-06
  • 2018-02-11
  • 2020-03-01
相关资源
最近更新 更多