PyGTK的“gdk”模块问题
Python的gtk
模块在导入一个叫gdk
的模块时,做了一些奇怪的操作。实际上,哪里都找不到一个真正的gdk
模块。gtk/__init__.py
模块的开头是这样的:
# load the required modules:
import gobject as _gobject
ver = getattr(_gobject, 'pygobject_version', ())
if ver < (2, 11, 1):
raise ImportError(
"PyGTK requires PyGObject 2.11.1 or higher, but %s was found" % (ver,))
if 'gtk._gtk' in sys.modules:
_gtk = sys.modules['gtk._gtk']
else:
from gtk import _gtk
import gdk
显然,gdk
就像雅典娜一样,从gtk
模块里包含的_gtk.so
共享库中突然出现。这样做没问题,但我现在遇到的问题是,使用weechat时,第一次加载一个使用gtk
的Python脚本是成功的,但之后就会出现像这样的错误信息:
python: loading script "/home/username/.weechat/python/lnotify.py"
python: stdout/stderr: Traceback (most recent call last):
python: stdout/stderr: File "/home/username/.weechat/python/lnotify.py", line 20, in <module>
python: stdout/stderr: import weechat, string, pynotify
python: stdout/stderr: File "/usr/lib64/python2.7/site-packages/gtk-2.0/pynotify/__init__.py", line 19, in <module>
python: stdout/stderr: import gtk
python: stdout/stderr: File "/usr/lib64/python2.7/site-packages/gtk-2.0/gtk/__init__.py", line 42, in <module>
python: stdout/stderr: import gdk
python: stdout/stderr: ImportError: No module named gdk
python: unable to parse file "/home/username/.weechat/python/lnotify.py"
所以,似乎发生了一些事情,让gtk
模块突然找不到共享库里的gdk
模块。我甚至不知道该从哪里开始排查这个问题,因为我不太确定是什么原因导致了这种符号解析的问题。
你之前见过这样的情况吗?
1 个回答
1
这个问题的根源在于,每个C扩展模块在一个进程中只会加载一次,而WeeChat在这个进程里使用了多个解释器实例,每个脚本一个。这种情况和扩展模块的工作方式不太兼容,原因有很多。
具体来说,模块的初始化只会在第一次导入扩展模块gtk._gtk
时运行,正如你所提到的,这时候gtk.gdk
才会被创建。从那以后,每次尝试import gtk
时,都会发现_gtk
已经被加载了,因此在新的解释器上下文中只会复制一份它的模块字典。这意味着你可以访问gtk._gtk
,但扩展的初始化函数不会再被调用,这就是为什么后续的解释器会缺少gtk.gdk
的原因。
你可以通过不使用WeeChat或子解释器,简单地导入gtk
,然后从sys.modules
中删除引用,再次导入gtk
来重现这种行为:
import sys
import gtk
for mod in sys.modules.keys():
if mod.startswith('gtk'):
sys.modules.pop(mod)
import gtk
# throws "ImportError: No module named gdk"
解决这个问题并不简单。你可以尝试:
- 修复PyGTK,使其使用一种与在不同解释器上下文中(重新)加载兼容的初始化程序
- 在WeeChat中为每个执行的脚本使用
fork()
,以提供真正的隔离(但在Windows上该怎么办呢?),这样可以避免这个问题,但会增加额外的开销。