staticmethod and namespaces

Diez B. Roggisch deets at nospam.web.de
Fri Feb 26 11:20:35 EST 2010


Am 26.02.10 17:08, schrieb Diez B. Roggisch:
> Am 26.02.10 16:57, schrieb darnzen:
>> On Feb 26, 9:41 am, "Diez B. Roggisch"<de... at nospam.web.de> wrote:
>>> Am 26.02.10 16:32, schrieb darnzen:
>>>
>>>
>>>
>>>
>>>
>>>> On Feb 26, 3:15 am, "Diez B. Roggisch"<de... at nospam.web.de> wrote:
>>>>> Am 26.02.10 06:07, schrieb darnzen:
>>>
>>>>>> Having an odd problem that I solved, but wondering if its the best
>>>>>> solution (seems like a bit of a hack).
>>>
>>>>>> First off, I'm using an external DLL that requires static callbacks,
>>>>>> but because of this, I'm losing instance info. It could be import
>>>>>> related? It will make more sense after I diagram it:
>>>
>>>>>> #Module main.py
>>>>>> from A import *
>>>
>>>>>> class App:
>>>>>> def sperg(self):
>>>>>> self.a = A()
>>>
>>>>>> app = App()
>>>>>> [main loop and such]
>>>>>> -----------------------------
>>>>>> # Module A.py
>>>>>> import main
>>>>>> class Foo:
>>>>>> Selves=[]
>>>>>> def __init__(self):
>>>>>> Foo.Selves.append(self)
>>>>>> @staticmethod
>>>>>> def chum_callback(nType, nP):
>>>>>> # Need to access function / data in app instance
>>>>>> app.sperg(nP)
>>>>>> # Need to access func data in Foo
>>>>>> # I'm pulling 'self' ouf of list made in constructor
>>>>>> self = Foo.getSelf(nP)
>>>
>>>>>> def getSelf(nP):
>>>>>> return self.Selves[nP]
>>>
>>>>>> ---------------------------------------------------------------------
>>>>>> So basically I added a list of instances to the base class so I can
>>>>>> get at them from the staticmethod.
>>>>>> What's bothering me the most is I can't use the global app
>>>>>> instance in
>>>>>> the A.py module.
>>>
>>>>>> How can I get at the app instance (currently I'm storing that along
>>>>>> with the class instance in the constructor)?
>>>>>> Is there another way to do this that's not such a hack?
>>>
>>>>>> Sorry for the double / partial post :(
>>>
>>>>> Can you show how you pass the staticmethod to the C-function? Is
>>>>> the DLL
>>>>> utilized by ctypes?
>>>
>>>>> I don't see any reason you couldn't use a bound method, which would
>>>>> give
>>>>> you your self, instead relying on global state.
>>>
>>>>> Diez
>>>
>>>> __main__.K<< *facepalm* should of tried that!
>>>
>>>> Yeah I'm using ctypes. The DLL callback set ups are as follows. The
>>>> local callback is in the App namespace (in this case, some callbacks
>>>> are in different modules as noted in OP), but still no access to self:
>>>
>>>> #Function wrapper
>>>> A.expCallback = WINFUNCTYPE(None, c_int, c_int, \
>>>> POINTER(Data_s))(A.Callback)
>>>
>>>> #DLL call to register the local callback function
>>>> DLLSetCallback(self.hID, A.SubID, EVENTID, A.expCallback)
>>>
>>>> class A:
>>>> #Local callback function
>>>> @staticmethod
>>>> def Callback(hID, SubID, Data):
>>>> print 'I DON'T KNOW WHO I AM OR WHERE I CAME FROM!!'
>>>> print 'BUT WITH hID, and SubID, I CAN FIGURE IT OUT'
>>>> print 'IF I STORE A REFERENCE TO MYSELF IN A DICT'
>>>> print 'USING KEY GENERATED FROM hID, SubID'
>>>> pass
>>>
>>>> I'm not sure why they need to be static callbacks, but the DLL doc's
>>>> say "when using object based languages, such as c++, callback
>>>> functions must be declared as static functions and not instance
>>>> methods", and I couldn't get it to work without setting it up that
>>>> way. I could probably have them all be "classless" functions, but with
>>>> 100's of these, my namespace would be polluted up the wazoo, and I'd
>>>> still have the problem that they wouldn't have access to instance
>>>> methods / properties.
>>>
>>> The above code can't work with self, because you use
>>>
>>> A.expCallback
>>>
>>> which at best can of course be a classmethod.
>>>
>>> You need to instead invoke DLLSetCallback with a bound method, like this
>>>
>>> a = A()
>>> DLLSetCallback(self.hID, A.SubID, EVENTID, a.expCallback)
>>>
>>> Also, the DLL-docs seem to refer to *C* or *C++*, where the concept of
>>> static functions is differently. If ctypes manages to get *some*
>>> callback passed, I'm 100% positive that it can pass *any* callable you
>>> like, including bound methods.
>>>
>>> Diez
>>
>> Thinking about it some more, I believe I understand why it has to be
>> staticfunction. To use an bound method would require the wrapper to
>> include a reference to the instance as follows:
>>
>> A.expCallback = WINFUNCTYPE(None, POINTER(A), c_int, c_int, \
>> POINTER(Data_s))(a.Callback)
>>
>> Since a = A(); a.foo() is really A.foo(self). The problem here is that
>> A is not a ctypes object and I can't change what arguments the DLL
>> uses in the callback in any case. Rewording my thoughts: a bound
>> method callback would require 'self' to be the first argument. I can
>> not make the DLL include 'self' as it doesn't know anything about the
>> objects in my program. Since I can't pass 'self', it has to be a
>> staticmethod.
>
> No, that's not true. A bound method implictly knows about it self, and
> it's a callable.
>
> What I guess is that you did the same mistake I did when I created that
> example - namely, not keeping a refernce to the bound method around.
> Ctypes will then garbage-collect the callback, which of course leads to
> all kinds of troubles.
>
> Try this:
>
> a = A()
> # keep this around
> bound_m = a.expCallback
> DLLSetCallback(self.hID, A.SubID, EVENTID, a.expCallback)

AAAAHHRG, same error again.

Of course, use

DLLSetCallback(self.hID, A.SubID, EVENTID, bound_m)

because the bound method changes with each time you create it.

Sorry for the confusion.

Diez



More information about the Python-list mailing list