8

有时我需要调用一个只存在于 C 中的 gtk/gobject 函数,但返回一个具有 python 包装器的对象。以前我使用了一个基于 ctypes 的解决方案,效果很好:

http://faq.pygtk.org/index.py?req=show&file=faq23.041.htp

现在我从 PyGtk(“import gtk”)切换到 GObject-introspection(“from gi.repository import Gtk”),我可以用什么来代替?

4

4 回答 4

8

_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 的必要函数。我想在那些时候你不得不放弃你最初的方法并尝试不同的东西。

于 2012-01-03T14:34:29.147 回答
4

jdm 的答案中的代码与 Python 3 不兼容。由于在 Python 2.7 和 3.1CObject中已弃用,并从 3.2 开始删除,我调整了要使用的代码Capsule(在 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 是否代表某种东西,但这样对我来说更有意义。)

于 2015-08-10T06:53:45.547 回答
2

自AlliedEnvy 更新以来,PyGOject api 发生了变化

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()
于 2017-04-04T16:06:57.693 回答
0

随着自省文件 ( .typelib, .gir) 的出现,无论使用何种语言,都应该可以使用相同的 API,也就是说,如果您使用的是 API 中没有的 C 函数,那么您可能正在使用打算使用的函数只在内部。

于 2011-12-29T17:36:29.873 回答