On Apr 21, 2005, at 8:59 PM, Josiah Carlson wrote:

Guido van Rossum <[EMAIL PROTECTED]> wrote:

[Brett]
I think I agree with Samuele that it would be more pertinent to put all of this
effort into trying to come up with some way to handle cleanup in a generator.

I.e. PEP 325.

But (as I explained, and you agree) that still doesn't render PEP 310
unnecessary, because abusing the for-loop for implied cleanup
semantics is ugly and expensive, and would change generator semantics;
and it bugs me that the finally clause's reachability depends on the
destructor executing.

Yes and no. PEP 325 offers a method to generators that handles cleanup if necessary and calls it close(). Obviously calling it close is a mistake. Actually, calling it anything is a mistake, and trying to combine try/finally handling in generators with __exit__/close (inside or outside of generators) is also a mistake.


Start by saying, "If a non-finalized generator is garbage collected, it
will be finalized." Whether this be by an exception or forcing a return,
so be it.


If this were to happen, we have generator finalization handled by the
garbage collector, and don't need to translate /any/ for loop. As long
as the garbage collection requirement is documented, we are covered (yay!).

Well, for the CPython implementation, couldn't you get away with using garbage collection to do everything? Maybe I'm missing something..


import weakref

class ResourceHandle(object):
    def __init__(self, acquire, release):
        acquire()
        # if I understand correctly, this is safer than __del__
        self.ref = weakref.ref(self, lambda o:release())

class FakeLock(object):
    def acquire(self):
        print "acquired"
    def release(self):
        print "released"

def with_lock(lock):
    r = ResourceHandle(lock.acquire, lock.release)
    yield None
    del r

>>> x = with_lock(FakeLock())
>>> del x
>>> with_lock(FakeLock()).next()
acquired
released
>>> for ignore in with_lock(FakeLock()):
...     print ignore
...
acquired
None
released

I could imagine someone complaining about generators that are never used missing out on the acquire/release. That could be solved with a trivial rewrite:

def with_lock(lock):
    def _with_lock(r):
        yield None
        del r
    return _with_lock(ResourceHandle(lock.acquire, lock.release))

>>> x = with_lock(FakeLock())
acquired
>>> del x
released

Of course, this just exaggerates Guido's "it bugs me that the finally clause's reachability depends on the destructor executing".. but it does work, in CPython.

It seems to me that this pattern would be painless enough to use without a syntax change...

-bob

_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to