类中的python访问dll回调函数中的self

2024-09-30 18:31:45 发布

您现在位置:Python中文网/ 问答频道 /正文

我有这样一个api的dll函数:

def dllcallback(items):
  pass

我想访问与dll回调链接的self in class函数。在

^{pr2}$

我不认为dllcallback接受自我作为论据。所以这次失败了。 我希望myobject.mycallback当api调用dllcallback时将触发,并显示:

999
888

我尝试了下面的方法让“self”可以被内部函数访问,但是这种方法扼杀了内核。。。在

class myobject(object):
  def __init__(self):
    self.a = 999
  def callbacks(self):
    @dllcallback
    def mycallback(items):
      print (self.a)
      self.a = 888
      print (self.a)

我不确定内核死的原因。提前谢谢你的建议。在

更新:20180912 1436

实际上,可以在没有self作为参数的情况下调用override方法

class myobject(object):
  def __init__(self):
    self.a = 999
  @dllcallback
  def mycallback(items):
    global self
    print (self.a)
    self.a = 888
    print (self.a)

NameError: name 'self' is not defined

我想“自我”不能这样得到…有什么建议吗?在

更新:20180913 1645

在编写包含ctypes dll回调函数的类方面取得了一些进展

class myobject(object):
  def __init__(self):
    if u'32bit' in architecture(): # 32bit WinOS
      self.spdll = windll.LoadLibrary('XXX.dll')
    else:                          # 64bit WinOS
      self.spdll = cdll.LoadLibrary('XXX.dll')
    self.a = 999

  def callbacksinit(self):
    def mycallback(items):
      print (self.a)
      self.a = 888
      print (self.a)
    self.mycallbackaddr = WINFUNCTYPE(None, c_char_p) 

  def regcallbacks(self):
    self.spdll.APICALLBACK(self.mycallbackaddr)

有了这段代码,当API触发mycallback时,我可以访问self.a。 对我来说幸运的是,在mycallback中没有全局声明(例如global self)的情况下,self.a可以在mycallback完成后更改为888。 我不知道为什么会这样…为什么WINFUNCTYPE(None,c_char_p)会这样工作,以及self.a在没有全局声明的情况下可以更改。我把这个问题留一段时间,也许有人可以澄清我的疑虑。在


Tags: 方法函数selfobjectinitdef情况items
2条回答

您的更新是有效的解决方案。您可以更新self,因为它是可变的。您不需要global(或者在本例中,nonlocal)声明来访问它。你只需要这些来重新分配变量。在

例如:

def func():
    L = []

    def inner():
        #nonlocal L  # Uncomment to work
        L = [1,2,3]  # Reassign L

    inner()          # Call the function and attempt to modify L
    return L

def func2():
    L = []

    def inner():
        L[:] = [1,2,3] # Mutate L

    inner()            # Call the function and attempt to modify L
    return L

print(func())
print(func2())

输出:

^{pr2}$

这里有一个完整的工作示例。。。在

测试c

#include <wchar.h>
#define API __declspec(dllexport)

typedef void (*CALLBACK)(const wchar_t*);

API void do_callback(CALLBACK cb)
{
    cb(L"one");
    cb(L"two");
    cb(L"three");
}

测试.py

from ctypes import *

CALLBACK = CFUNCTYPE(None,c_wchar_p)

class Test:
    dll = CDLL('test')
    dll.do_callback.argtypes = CALLBACK,
    dll.do_callback.restype = None

    def __init__(self):
        self.count = 0

    def get_callback(self):

        @CALLBACK
        def callback(s):
            self.count += 1     # nonlocal, but mutable
            print(self.count,s)

        return callback

    def do(self):
        self.dll.do_callback(self.get_callback())

t = Test()
t.do()

输出:

1 one
2 two
3 three

Python有一种神奇的方法可以在回调中找到method+实例。但当你与另一种语言交流时,那就另当别论了。在

不确定是否可以做得更好:

  • 在全局(类实例)字典中注册对象
  • 创建一个回调包装函数来查找id(调用者必须知道),并使用适当的上下文调用方法

您可以将所有静态对象保留在类范围内,以获得更干净的解决方案。在

像这样:

class myobject(object):
  globdict = {}
  id = 0
  def __init__(self):
    self.a = 999
    self.id += 1   # this id will have to be passed to the foreign library
    myobject.globdict[self.id] = self

  def mycallback(self, items):
    print (self.a)

  @staticmethod
  def real_callback(id,items):
     # first parameter is the object, then the "items" argument
     # using function-call style (not object)
     # id may need to be converted back from `ctypes`
     myobject.mycallback(myobject.globdict[id],items)

相关问题 更多 >