[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/)