入れ子関数を使用するVideoクラスのコンテキストでは、次のようになります。
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関数への参照を保存して、ガベージコレクションが行われないようにします。