【问题标题】:Create python object from memory address (using gi.repository)从内存地址创建 python 对象(使用 gi.repository)
【发布时间】:2012-01-29 21:35:06
【问题描述】:

有时我需要调用一个只存在于 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"),我可以改用什么?

【问题讨论】:

    标签: python ctypes pygobject


    【解决方案1】:

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

    【讨论】:

      【解决方案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()
      

      (我还将它重命名为 PyGobjectCAPI——不确定 CPAI 是否代表某种东西,但这样对我来说更有意义。)

      【讨论】:

        【解决方案3】:

        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()
        

        【讨论】:

          【解决方案4】:

          随着自省文件(.typelib.gir)的出现,无论使用哪种语言,都应该可以使用相同的 API,也就是说,如果您使用的是 API 中没有的 C 函数,则re 可能使用了一个仅供内部使用的函数。

          【讨论】:

          • 理论上是这样。但是我想使用 libdconf 中的一个函数,目前在我的操作系统(Ubuntu Oneric)上没有绑定。此外,可以想象必须处理返回指向 GObject 的指针的自定义库(不是 Gtk & co. 的一部分),因此在特殊情况下这仍然可能有用。
          猜你喜欢
          • 1970-01-01
          • 2010-12-06
          • 1970-01-01
          • 1970-01-01
          • 2013-04-27
          • 1970-01-01
          • 2018-09-08
          • 2010-09-12
          • 2016-11-22
          相关资源
          最近更新 更多