有时候我需要调用一个只存在于C中的gtk / gobject函数,但返回一个带有python包装器的对象。以前我使用过基于ctypes的解决方案,效果很好:
http://faq.pygtk.org/index.py?req=show&file=faq23.041.htp
现在我从PyGtk(“import gtk”)开始转向GObject-introspection(“来自gi.repository import Gtk”),我可以使用什么呢?
答案 0 :(得分:6)
_PyGObject_API
界面在某些时候发生了变化。我需要放弃register_sinkfunc
功能。以下作品:
from gi.repository import Gio, GLib
import gi
import ctypes
class _PyGObject_Functions(ctypes.Structure):
_fields_ = [
('register_class',
ctypes.PYFUNCTYPE(ctypes.c_void_p, ctypes.c_char_p,
ctypes.c_int, ctypes.py_object,
ctypes.py_object)),
('register_wrapper',
ctypes.PYFUNCTYPE(ctypes.c_void_p, ctypes.py_object)),
('lookup_class',
ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_int)),
('newgobj',
ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_void_p)),
]
class PyGObjectCPAI(object):
def __init__(self):
PyCObject_AsVoidPtr = ctypes.pythonapi.PyCObject_AsVoidPtr
PyCObject_AsVoidPtr.restype = ctypes.c_void_p
PyCObject_AsVoidPtr.argtypes = [ctypes.py_object]
addr = PyCObject_AsVoidPtr(ctypes.py_object(
gi._gobject._PyGObject_API))
self._api = _PyGObject_Functions.from_address(addr)
def pygobject_new(self, addr):
return self._api.newgobj(addr)
capi = PyGObjectCPAI()
从指针获取对象:
obj = capi.pygobject_new(pointer)
从(g)对象获取指针:
pointer = hash(obj)
我必须补充一下,在我的情况下,这并没有帮助我解决我的实际问题。我试图与dconf接口,但dconf返回GVariant类型的值,它不从GObject继承。遗憾的是,PyGI / GObject似乎没有公开必要的函数来将C(* GVariant)变成Python GLib.Variant。我想那时候你必须抛弃你的初始方法并尝试不同的东西。
答案 1 :(得分:2)
jdm's answer中的代码与Python 3不兼容。由于CObject
在Python 2.7和3.1中是deprecated,并且从3.2开始删除,我将代码调整为使用Capsule
(available在2.7和3.1中):
import ctypes, gi
class _PyGObject_Functions(ctypes.Structure):
_fields_ = [
('register_class',
ctypes.PYFUNCTYPE(ctypes.c_void_p, ctypes.c_char_p,
ctypes.c_int, ctypes.py_object, ctypes.py_object)),
('register_wrapper',
ctypes.PYFUNCTYPE(ctypes.c_void_p, ctypes.py_object)),
('lookup_class',
ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_int)),
('newgobj',
ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_void_p)),
]
class PyGObjectCAPI(object):
def __init__(self):
self._as_void_ptr.restype = ctypes.c_void_p
self._as_void_ptr.argtypes = [ctypes.py_object]
addr = self._as_void_ptr(ctypes.py_object(
gi._gobject._PyGObject_API))
self._api = _PyGObject_Functions.from_address(addr)
@staticmethod
def _as_void_ptr(obj):
name = ctypes.pythonapi.PyCapsule_GetName(obj)
return ctypes.pythonapi.PyCapsule_GetPointer(obj, name)
def pygobject_new(self, addr):
return self._api.newgobj(addr)
capi = PyGObjectCAPI()
(我也将它重命名为PyGobjectC API - 不确定CPAI代表什么,但这样对我来说更有意义。)
答案 2 :(得分:1)
PyGOject api自AlliedEnvy update
以来发生了变化import gi
import ctypes
from ctypes import pythonapi
class _PyGObject_Functions(ctypes.Structure):
_fields_ = [
('pygobject_register_class',
ctypes.PYFUNCTYPE(ctypes.c_void_p)),
('pygobject_register_wrapper',
ctypes.PYFUNCTYPE(ctypes.c_void_p)),
('pygobject_lookup_class',
ctypes.PYFUNCTYPE(ctypes.c_void_p)),
('pygobject_new',
ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_void_p)),
]
class PyGObjectCAPI(object):
def __init__(self):
addr = self._as_void_ptr(gi._gobject._PyGObject_API)
self._api = _PyGObject_Functions.from_address(addr)
@classmethod
def _capsule_name(cls, capsule):
pythonapi.PyCapsule_GetName.restype = ctypes.c_char_p
pythonapi.PyCapsule_GetName.argtypes = [ctypes.py_object]
return pythonapi.PyCapsule_GetName(capsule)
@classmethod
def _as_void_ptr(cls, capsule):
name = cls._capsule_name(capsule)
pythonapi.PyCapsule_GetPointer.restype = ctypes.c_void_p
pythonapi.PyCapsule_GetPointer.argtypes = [
ctypes.py_object, ctypes.c_char_p]
return pythonapi.PyCapsule_GetPointer(capsule, name)
def to_object(self, addr):
return self._api.pygobject_new(addr)
capi = PyGObjectCAPI()
答案 3 :(得分:0)
随着instrospection文件(.typelib
,.gir
)的出现,无论使用何种语言,都应该可以使用相同的API,也就是说,如果你使用的是C函数,那么API,您可能正在使用仅在内部使用的函数。