В контексте Класс видео с использованием вложенной функции:
class Video(object):
def __init__(self, ...):
self.__cbFileRefDone = []
def open(self, filename):
@WINFUNCTYPE(None, DWORD, DWORD)
def cbFileRefDone(port, user_data):
print "File indexed.", filename
self.__cbFileRefDone.append(cbFileRefDone) # save reference
if not self.hsdk.PlayM4_SetFileRefCallBack(
c_long(self.port), cbFileRefDone, DWORD(0)):
logging.error("Unable to set callback for indexing")
return False
Это несколько уродливо, но более естественный вариант завершается с TypeError во время обратного вызова:
#XXX this won't work
@WINFUNCTYPE(None, DWORD, DWORD)
def cbFileRefDone(self, port, user_data):
print "File indexed."
Чтобы исправить это, можно создать специальный дескриптор функции:
def method(prototype):
class MethodDescriptor(object):
def __init__(self, func):
self.func = func
self.bound_funcs = {} # hold on to references to prevent gc
def __get__(self, obj, type=None):
assert obj is not None # always require an instance
try: return self.bound_funcs[obj,type]
except KeyError:
ret = self.bound_funcs[obj,type] = prototype(
self.func.__get__(obj, type))
return ret
return MethodDescriptor
Использование:
class Video(object):
@method(WINFUNCTYPE(None, DWORD, DWORD))
def cbFileRefDone(self, port, user_data):
print "File indexed."
def open(self, filename):
# ...
self.hsdk.PlayM4_SetFileRefCallBack(
c_long(self.port), self.cbFileRefDone, DWORD(0))
Кроме того, MethodDescriptor сохраняет ссылки на функции C, чтобы предотвратить их сборку мусора.