[Python-Dev] Weakref design questions
Guido van Rossum
guido@python.org
Fri, 18 Oct 2002 20:23:50 -0400
> 1. Is there any reason why builtin methods cannot be proxied?
The instances of a type need to have a pointer added if the type is to
support weak refs to its instances. We've only done this for the
obvious candidates like user-defined class instances and a few
others. You must weigh the cost of the extra pointer vs. the utility
of being able to use weak refs for a particular type.
> 2. It would be handy for my application if a callback could be triggered
> when an object has no more weak references attached to it.
>
> It seems like my application could be a fairly common one:
>
> # C library pseudocode
> def c_library_func(): # C code
> while 1:
> o = create_complex_object()
> user_call_back(o)
> del o
>
> # Python bindings pseudocode
> def python_bindings_user_call_back (o): # C code
> py_o = create_python_wrapper_object(o)
> proxy = PyWeakref_NewProxy(py_o)
> python_function(py_o)
> Py_DECREF(proxy)
> Py_DECREF(py_o) # This will kill the proxy
>
>
> # Evil Python user code
> evil = None
> def python_function(o):
> global evil
> o.foo()
> evil = o
>
> start(python_function)
> evil.foo() # Nice exception because evil is a dead proxy
>
> # More evil Python user code
>
> more_evil = None
> def python_function(o):
> global more_evil
> o.foo()
> more_evil = o.foo
>
> start(python_function)
> more_evil() # Crash because the underlying data structures that
> # the Python wrapper object depends on are dead
>
> My current solution to this problem is to create my own callable object
> type that supports weakrefs. That object is then used to wrap the real
> bound method object e.g.
>
> def getattr(self, name): # This is C code
> callable = MyCallAble_New(Py_FindMethod(...);
> objects_to_kill_after_py_func_call.add(callable);
> return PyWeakref_NewProxy(callable);
>
> Avoiding this hassle is the reason for my question.
>
> Pruning callable objects that the user is done with is the reason for my
> request.
I'm sorry, but I don't understand why you're using weak references
here at all. Is it really the proxy function that you're after? If
you're worried about the complex object 'o' being referenced after the
C library has killed it (a ligitimate concern), while the Python
wrapper can be kept alive using the scenario you show, the Python
wrapper py_o should set its pointer to 'o' to NULL when o's lifetime
ends (or a little before) and make sure that methods on the wrapper
raise an exception when the reference is NULL.
This is how all well-behaved wrapper objects behave; e.g. file and
socket objects in Python check if the file is closed in each method
implementation.
--Guido van Rossum (home page: http://www.python.org/~guido/)