staticmethod and namespaces

D

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 :(
 
S

Steven D'Aprano

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. [...]
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?

Pass the instance explicitly:
.... @staticmethod
.... def static(self, x, y):
.... print self, x, y
....<__main__.K object at 0xb7c2544c> 1 2
 
D

Diez B. Roggisch

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
 
D

darnzen

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.
 
D

Diez B. Roggisch

Am 26.02.10 16:32, schrieb darnzen:
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
 
D

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. [...]
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?

Pass the instance explicitly:

...     @staticmethod
...     def static(self, x, y):
...         print self, x, y
...>>> k = K()
<__main__.K object at 0xb7c2544c> 1 2

Unfortunately, since the callback is from the DLL which I didn't
write, I can not change what is passed to the function. Also, the DLL
has no idea about my local namespace. The DLL typically will pass back
two integers (which I can set the values of when I register the
callback), and some data. Currently Im' using these integers as keys
in a local dict where I'm storing the instances.

I suppose I could use the integers to store the high and low order
bytes of a pointer to the instance, but not sure how to do that in
Python (would be easy in c/c++). Also, I'm not sure how python memory
management works, if it will move objects around and make things
buggy. Also, that is definitely a hack and isn't very 'pythonesque'
 
D

darnzen

Am 26.02.10 16:32, schrieb darnzen:




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

This was originally how my code was set up, invoking with the bound
methods, but it didn't work (crashing and bizzaro errors) and I was
pulling my hair out. Then I read the documentation and changed it to
static methods and everything started working. Believe me, I totally
understand how using bound methods would make this problem go away.
 
D

darnzen

Am 26.02.10 16:32, schrieb darnzen:




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.
 
D

Diez B. Roggisch

Am 26.02.10 16:57, schrieb darnzen:
Am 26.02.10 16:32, schrieb darnzen:




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.

__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)

Diez
 
D

Diez B. Roggisch

Am 26.02.10 17:08, schrieb Diez B. Roggisch:
Am 26.02.10 16:57, schrieb darnzen:
Am 26.02.10 16:32, schrieb darnzen:





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
 
D

darnzen

Am 26.02.10 17:08, schrieb Diez B. Roggisch:




Am 26.02.10 16:57, schrieb darnzen:
Am 26.02.10 16:32, schrieb darnzen:
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

Well, I got around this mess by putting all those static callbacks
into a separate module in a new class. I set them up to call a bound
method of that class which passes the arguments to the appropriate
bound methods of other class instances. I just have to keep a little
dict of the bound method callbacks when I register them with the
class.

I also found a simple trick for sharing globals between modules.
Pretty simple, create an empty module, say shared.py, with only the
pass statement in it. Then dynamically add properties to it such as
shared.app = App(). Import shared into the modules that need access to
app and done!

Thanks for the help on this. Always learning!
 
G

Gregory Ewing

darnzen said:
Well, I got around this mess by putting all those static callbacks
into a separate module in a new class. I set them up to call a bound
method of that class which passes the arguments to the appropriate
bound methods of other class instances. I just have to keep a little
dict of the bound method callbacks when I register them with the
class.

You're making it much more complicated than it needs to
be. Diez is right, a bound method should work provided you
keep a reference to it somewhere for as long as it's needed.
 
Ð

Дамјан ГеоргиевÑки

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:

Have you tried using a closure, something like this:

class A:
def call(self, args):
def callback(a, b): # normal function
# but I can access self here too
call_the_dll_function(callback, args1, args2...)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top