Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #4166
| Path | csiph.com!x330-a1.tempe.blueboxinc.net!usenet.pasdenom.info!aioe.org!feeder.news-service.com!newsfeed.xs4all.nl!newsfeed6.news.xs4all.nl!xs4all!post.news.xs4all.nl!not-for-mail |
|---|---|
| Return-Path | <ms419@freezone.co.uk> |
| X-Original-To | python-list@python.org |
| Delivered-To | python-list@mail.python.org |
| X-Spam-Status | OK 0.000 |
| X-Spam-Evidence | '*H*': 1.00; '*S*': 0.00; 'python,': 0.01; 'circular': 0.03; 'handled': 0.03; 'sys': 0.04; 'formed': 0.07; 'method,': 0.07; 'pep': 0.07; 'python)': 0.07; 'python': 0.07; "(it's": 0.09; 'called.': 0.09; 'cleaned': 0.09; 'garbage': 0.09; 'python-level': 0.09; 'referenced': 0.09; 'restriction': 0.09; 'subject:object': 0.09; 'def': 0.13; '(below).': 0.16; '(excluding': 0.16; 'callback': 0.16; 'default),': 0.16; 'destructor': 0.16; 'leaks': 0.16; 'received:96.54': 0.16; 'scope,': 0.16; 'subject:exists': 0.16; 'invalid': 0.16; 'exists': 0.19; 'object,': 0.19; 'variable': 0.21; 'code': 0.22; 'e.g.': 0.22; 'subject:code': 0.23; 'world!': 0.23; 'objects': 0.24; 'example': 0.24; 'memory': 0.24; 'skip:# 10': 0.25; 'suspect': 0.25; 'object': 0.27; "doesn't": 0.28; 'class': 0.29; "python's": 0.29; 'cycles': 0.31; 'detector': 0.31; 'enabled': 0.31; 'received:96': 0.31; "can't": 0.31; 'import': 0.32; 'called': 0.32; 'to:addr:python-list': 0.32; 'option': 0.33; 'creates': 0.33; 'reference': 0.34; 'received:192': 0.34; 'skip:" 10': 0.34; 'received:70': 0.34; 'there': 0.35; 'print': 0.35; 'point': 0.35; 'received:192.168': 0.37; 'some': 0.37; 'however': 0.37; 'self': 0.37; 'should': 0.37; 'cycle': 0.38; 'references': 0.38; 'but': 0.38; 'current': 0.38; 'signal': 0.39; 'to:addr:python.org': 0.39; 'header:Mime-Version:1': 0.39; 'how': 0.39; 'works': 0.40; 'behavior': 0.40; "it's": 0.40; 'subject': 0.61; 'order': 0.61; 'cause': 0.65; 'below,': 0.71; 'exotic': 0.84; 'off"': 0.84; 'reachable': 0.84; 'reference?': 0.84; 'tricky': 0.84; 'involved.': 0.91; 'killed': 0.91; 'subject:call': 0.91 |
| X-Cloudmark-SP-Filtered | true |
| X-Cloudmark-SP-Result | v=1.1 cv=l0hTUOwXBBZC3xuFbE1ochJnP84ph5EBJB8ZSEz2E7A= c=1 sm=1 a=ce0y7WToGDYA:10 a=qWYXSweIvAIA:10 a=BLceEmwcHowA:10 a=LYYm-LO_OfoA:10 a=RBKHmHSr9-IA:10 a=IkcTkHD0fZMA:10 a=b0KxtKZxmKbTALECVfpD+Q==:17 a=ix6Hxt0jKgOGdwMXI3EA:9 a=iI5xN9I5EabL2H6nA7AA:7 a=QEXdDO2ut3YA:10 a=HpAAvcLHHh0Zw7uRqdWCyQ==:117 |
| X-IronPort-AV | E=Sophos;i="4.64,276,1301896800"; d="scan'208";a="427297414" |
| X-reinject | true |
| Subject | Reliably call code after object no longer exists or is "unreachable"? |
| From | Jack Bates <ms419@freezone.co.uk> |
| To | python-list@python.org |
| Content-Type | text/plain; charset="UTF-8" |
| Content-Transfer-Encoding | quoted-printable |
| Date | Wed, 27 Apr 2011 09:48:42 -0700 |
| Mime-Version | 1.0 |
| X-Mailer | Evolution 2.32.2 |
| X-BeenThere | python-list@python.org |
| X-Mailman-Version | 2.1.12 |
| Precedence | list |
| List-Id | General discussion list for the Python programming language <python-list.python.org> |
| List-Unsubscribe | <http://mail.python.org/mailman/options/python-list>, <mailto:python-list-request@python.org?subject=unsubscribe> |
| List-Archive | <http://mail.python.org/pipermail/python-list> |
| List-Post | <mailto:python-list@python.org> |
| List-Help | <mailto:python-list-request@python.org?subject=help> |
| List-Subscribe | <http://mail.python.org/mailman/listinfo/python-list>, <mailto:python-list-request@python.org?subject=subscribe> |
| Newsgroups | comp.lang.python |
| Message-ID | <mailman.912.1303940829.9059.python-list@python.org> (permalink) |
| Lines | 133 |
| NNTP-Posting-Host | 82.94.164.166 |
| X-Trace | 1303940830 news.xs4all.nl 81473 [::ffff:82.94.164.166]:45635 |
| X-Complaints-To | abuse@xs4all.nl |
| Xref | x330-a1.tempe.blueboxinc.net comp.lang.python:4166 |
Show key headers only | View raw
In Python, how can you reliably call code - but wait until an object no
longer exists or is "unreachable"?
I want to ensure that some code is called (excluding some exotic
situations like when the program is killed by a signal not handled by
Python) but can't call it immediately. I want to wait until there are no
references to an object - or the only references to the object are from
unreachable reference cycles
#!/usr/bin/env python
class Goodbye:
def __del__(self):
print 'Goodbye, world!'
ref = Goodbye()
$ ./goodbye
Goodbye, world!
$
Python's __del__ or destructor method works (above) - but only in the
absence of reference cycles (below). An object, with a __del__ method,
in a reference cycle, causes all objects in the cycle to be
"uncollectable". This can cause memory leaks and because the object is
never collected, its __del__ method is never called
> Circular references which are garbage are detected when the option
> cycle detector is enabled (it's on by default), but can only be
> cleaned up if there are no Python-level __del__() methods involved.
#!/usr/bin/env python
class Goodbye:
def __del__(self):
print 'Goodbye, world!'
class Cycle:
def __init__(self, cycle):
self.next = cycle
cycle.next = self
Cycle(Goodbye())
$ ./cycle
$
In PEP 342 I read that an object, with a __del__ method, referenced by a
cycle but not itself participating in the cycle, doesn't cause objects
to be uncollectable. If the cycle is "collectable" then when it's
eventually collected by the garbage collector, the __del__ method is
called
> If the generator object participates in a cycle, g.__del__() may not
> be called. This is the behavior of CPython's current garbage
> collector. The reason for the restriction is that the GC code needs to
> "break" a cycle at an arbitrary point in order to collect it, and from
> then on no Python code should be allowed to see the objects that
> formed the cycle, as they may be in an invalid state. Objects "hanging
> off" a cycle are not subject to this restriction.
#!/usr/bin/env python
import sys
class Destruct:
def __init__(self, callback):
self.__del__ = callback
class Goodbye:
def __init__(self):
self.destruct = Destruct(lambda: sys.stdout.write('Goodbye, world!\n'))
class Cycle:
def __init__(self, cycle):
self.next = cycle
cycle.next = self
Cycle(Goodbye())
$ ./dangle
Goodbye, world!
$
However it's *extremely* tricky to ensure that the object with a __del__
method doesn't participate in a cycle, e.g. in the example below, the
__del__ method is never called - I suspect because the object with a
__del__ method is reachable from the global scope, and this forms a
cycle with a frame's f_globals reference? "storing a generator object in
a global variable creates a cycle via the generator frame's f_globals
pointer"
#!/usr/bin/env python
import sys
class Destruct:
def __init__(self, callback):
self.__del__ = callback
class Goodbye:
def __init__(self):
self.destruct = Destruct(lambda: sys.stdout.write('Goodbye, world!\n'))
class Cycle:
def __init__(self, cycle):
self.next = cycle
cycle.next = self
ref = Cycle(Goodbye())
$ ./global
$
Faced with the real potential for reference cycles, how can you reliably
call code - but wait until an object no longer exists or is
"unreachable"?
Back to comp.lang.python | Previous | Next — Next in thread | Find similar
Reliably call code after object no longer exists or is "unreachable"? Jack Bates <ms419@freezone.co.uk> - 2011-04-27 09:48 -0700 Re: Reliably call code after object no longer exists or is "unreachable"? Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2011-04-28 02:54 +0200 Re: Reliably call code after object no longer exists or is "unreachable"? Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2011-04-28 19:13 +1200
csiph-web