我有一些api的dll函数,如下所示:
def dllcallback(items):
pass
我想访问与dll回调链接的类函数中的self。
class myobject(object):
def __init__(self):
self.a = 999
@dllcallback
def mycallback(self, items):
print (self.a)
self.a = 888
print (self.a)
我不认为dllcallback接受self作为参数。所以这失败了。 我希望当api调用dllcallback时触发myobject.mycallback并显示:
999
888
并且我尝试通过以下方法使内部函数可以访问“自我”,但是这种方法杀死了内核...
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触发时,我可以访问self.a。 对我来说幸运的是,在mycallback完成后无需在mycallback中进行全局声明(例如global self)的情况下,self.a可以更改为888。 我不知道为什么会这样...为什么WINFUNCTYPE(None,c_char_p)以这种方式工作,为什么self.a可以在没有全局声明的情况下进行更改。我暂时不提这个问题,也许有人可以消除我的疑虑。
答案 0 :(得分:1)
Python有一种神奇的方法可以在回调中找到方法+实例。但是,当您与另一种语言进行交互时,那就是另一回事了。
不确定是否可以做得更好:
您可以将所有静态对象保留在类范围内,以获得更清洁的解决方案。
像这样:
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)
答案 1 :(得分:1)
您的更新是有效的解决方案。您可以更新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())
输出:
[]
[1, 2, 3]
这是您的方法的完整示例...
test.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");
}
test.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