is there anybody using __del__ correctly??

Michele Simionato michele.simionato at gmail.com
Mon Aug 13 01:58:42 EDT 2007


On Aug 12, 9:14 pm, Steven Bethard <steven.beth... at gmail.com> wrote:
> Michele Simionato wrote:
> > On Aug 10, 7:09 pm, Steven Bethard <steven.beth... at gmail.com> wrote:
> >> There were also a few recipes posted during this discussion that wrap
> >> weakrefs up a bit nicer so it's easier to use them in place of __del__:
>
> >>http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/519635
>
> > I knew about your recipe and I thought it was clever, *very*
> > clever. I have been thinking about it a bit more today and
> > here is an alternative, which does not require metaclasses,
> > does not require descriptors, and does not require the user to
> > declare the attributes she will use in the __finalize__ method.
> > Warning: it is no more tested than the test case in your recipe:
>
> > import weakref
>
> > _get = object.__getattribute__
> > _set = object.__setattr__
> > _del = object.__delattr__
>
> > def getinnerobj(self):
> >     return _get(self, '*innerobj*')
>
> > class Impostor(object):
> >     "It tries very hard to impersonate the inner object"
> >     def __init__(self, obj):
> >         _set(self, '*innerobj*', obj)
> >     def __getattribute__(self, name):
> >         return getattr(getinnerobj(self), name)
> >     def __setattr__(self, name, value):
> >         _set(getinnerobj(self), name, value)
> >     def __delattr__(self, name):
> >         _del(getinnerobj(self), name)
>
> > _refset = set()
>
> > class Finalized(object):
> >     def __new__(cls, *args, **kw):
> >         self = super(Finalized, cls).__new__(cls, *args, **kw)
> >         self.__init__(*args, **kw)
> >         def finalize(ref, refset=_refset):
> >             refset.remove(ref)
> >             cls.__finalize__(self)
> >         fake = Impostor(self)
> >         _refset.add(weakref.ref(fake, finalize))
> >         return fake
> >     def __finalize__(self):
> >         pass
>
> The problem here is that __getattribute__ doesn't work for things like
> __getitem__.

Yeah, it is the old issue of special methods being special, i.e.
len(x)
is not exactly x.__len__(). I am not sure if this can be changed in
Py3k,
it is certainly annoying in some (rare) circumstances, as
here.
One workaround is to add all special methods to the Impostor
class:

SPECIALMETHODS = ['__%s__' % name for name in
'''
abs add and call concat contains delitem delslice div eq floordiv ge
getitem
getslice gt iadd iand iconcat idiv ifloordiv ilshift imod imul index
inv invert
ior ipow irepeat irshift isub iter itruediv ixor le len lshift lt mod
mul ne neg
not or pos pow repeat repr rshift setitem setslice str sub truediv
xor
'''.split()]

def add_special_method(cls,
name):                                                             def
meth(self,
*args):
        return getattr(self, name)
(*args)
    meth.__name__ =
name
    setattr(cls, name,
meth)
for name in
SPECIALMETHODS:
    add_special_method(Impostor,
name)

In this way the Impostor can emulate even the special methods. Here is
an
example:

>>> class C(object):
...
pass
...
>>> c=Impostor(C())
>>> print c
<__main__.C object at
0x102a390>

Notice that the impostor is calling the __str__ method of C, so it
really
looks like a C object.
Moreover

>>> c.__class__
<class
'__main__.C'>

and

>>> isinstance(c, C)
True

so the Impostor is doing a damn pretty good job of imposture for C
objects.
Of course it does what it can, and it cannot impersonate C objects
completely:
>>> type(c)
<class
'__main__.Impostor'>

so code using checks like ``type(c) is C`` would break and the
approach here
cannot be considered more than a hack. Still a cool hack, I would
say ;)

    Michele Simionato




More information about the Python-list mailing list