Bruno Desthuilliers wrote: > Mathias Panzenboeck a écrit : > > About the lost weakref problem: in Python, methods are just tiny > wrappers around the object, class and function created at lookup time > (yes, on *each* lookup) (and WWAI, they are by the function object > itself, which implements the descriptor protocol). > >> When I change the class Wrapper to following, the class Foo works: >> >> class Wrapper(object): >> def __init__(self,x): >> self.func_name = x.func_name >> self.x = weakref.ref(x.im_self) > >> def __call__(self,*args,**kwargs): >> x = self.x() >> if x is None: >> print "lost reference" >> else: >> return getattr(x,self.func_name)(*args,**kwargs) > > Anyway, the whole thing looks quite baroque to me - and I'm known for my > immoderate appetite for brain-melting features.... > > If I understand correctly, you're doing all this to avoid circular > references while keeping track of a list of methods to call ? > > If yes, then you're thru much pain for nothing. Mostly because there are > other much more simpler solutions. The first one is obviously to use > names and getattr. In it's most naïve implementation, this would look like: > > class Foo(object): > def __init__(self): > self._methods = set() > self._methods.add('_foo') > > def _foo(self): > print "_foo" > > def callMethods(self): > for name in self._methods: > meth = getattr(self, name, None) > if callable(meth): > meth() > > > > > Now if _methods is supposed to have the same content class-wise (which > is the case in your exemple), no need to have it as an instance method: > > class Foo(object): > _methods = set('_foo') > > def _foo(self): > print "_foo" > > def callMethods(self): > for name in self._methods: > meth = getattr(self, name, None) > if callable(meth): > meth() > > We could go further, like using a decorator to mark methods to add to > _methods, and a metaclass to set the whole thing up, but this would > probably be overkill. Unless there are other requirements, I'd > personnaly stop here. > > Oh, and yes, while we're at it : Python usually knows how to deal with > circular references.... >
Well yes and no. It does with the enabled gc but I like refcounting much more because of the predictable behaviour. And when there are no refloops, refcounting makes no problems. However, Alex Martelli already showed a great way to do what I need, see: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81253 I need it for a little UI lib. Well lib is too much. Just a small wrapper around blenders unusable API for building GUIs for your scripts. It's ugly as hell. I made very few classes to wrap up that crap. Every input widget in my UI lib has an action. You can register action listeners like this: def actionListener(value): print "new value:",value widget.addActionListener(actionListener) When an widget itself want's to listen for it's action and does this in __init__: self.addActionListener(sefl.__actionListener) there would be a ref loop. Therefore I do this now: self.addActionListener(WeakListener(sefl.__actionListener)) And WeakListener I implemented as follows: class WeakListener(object): __slots__ = ('__weakref__', '_func','_obj') def __init__(self,listener): self._func = listener.im_func self._obj = weakref.ref(listener.im_self) def __call__(self,*args,**kwargs): obj = self._obj() if obj is None: print "*** lost reference to %s's self object ***" % \ self._func.func_name else: self._func(obj,*args,**kwargs) Could be better/more generic, but that's all I need. To implement the action listener by overloading a action method is IMHO a bad idea. Because that would kill the listener of the base class. Explicitly calling the base classes action method is ugly and error prone. And when I have to register action listeners from "outside" the widget, too. But thanks for your reply. :) -panzi -- http://mail.python.org/mailman/listinfo/python-list