[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] PixelArray question



On 8/26/07, Marcus von Appen <mva@xxxxxxxxxxxx> wrote:
> >    sf = pygame.Surface ((10, 20))
> >    sf.fill ((0, 0, 0))
> >    with PixelArray(sf) as p:
> >        buffer_request(p)
> >
> > The PixelArray __enter__ method simply returns self. __exit__ unlocks the
> > parent surface and invalidates the array.
>
> That's definitely something that should be supported once Python 2.6 is
> available. As far as I understand p's lifetime will be limited to the
> with ... : block anyhow, so it'll be (implicitly) deleted once the scope
> is left (and the surface thus will be automatically unlocked - even in
> the current implementation).
> For now it's nothing we need to take care of however.
>
looking at the PEP fro the with statement, I don't think the "with"
statement will affect anything about when the pixelarray object will
be deleted, and moreover I don't see any reason to think p's lifetime
would be limited to the with block (the p is optional)
http://www.python.org/dev/peps/pep-0343/

it seems that Lenard's code block there would be translated to this:
        sf = pygame.Surface ((10, 20))
        sf.fill ((0, 0, 0))
        mgr = (EXPR)
        exit = mgr.__exit__  # Not calling it yet
        value = mgr.__enter__()
        exc = True
        try:
            try:
                p = value  # Only if "as VAR" is present
                buffer_request(p)
            except:
                # The exceptional case is handled here
                exc = False
                if not exit(*sys.exc_info()):
                    raise
                # The exception is swallowed if exit() returns true
        finally:
            # The normal and non-local-goto cases are handled here
            if exc:
                exit(None, None, None)

That code looks to me like the following would happen in this order:
1. PixelArray object is constructed
2. the PixelArray __enter__ method is executed and the return value is p
3. the block inside the with statement is executed
4. the PixelArray __exit__ method is executed
5. the PixelArray object and whatever is returned from __enter__
delete sometime after the scope block containing the with is done

my point being that it seems that if one made __enter__ and __exit__
do automatic surface locking, that it would be in addition to any
object constructor and destructor automatic surface locking, and
doesn't affect the destructor timing in a significant way. Meaning if
either were implemented naively, it seems enter and exit locking would
just add one more lock. Maybe a __enter__ could "take over" the
constructor lock (so destructor wouldn't unlock) so __exit__ would do
the unlock instead

Also, even though support for this isn't all that important until 2.6,
the PEP says with can be used and supported with this import line:
    from __future__ import with_statement

...I could be totally wrong though so I wrote a testscript that looks
at how it all goes down with print statements. I wasn't able to test
the actual "with" statement (I don't have access to python 2.5 right
now) though
import sys
from __future__ import with_statement

class SourceClass(object):
    def __init__(self):
        print "SourceClass.__init__"

    def __del__(self):
        print "SourceClass.__del__"
        
class TestClass(object):
    def __init__(self, thing):
        print "TestClass.__init__"
        self.thing = thing
        
    def __enter__(self):
        print "TestClass.__enter__"
        return self

    def do_work_on(self):
        print "TestClass.do_work_on"

    def check_if_exists(self):
        print "TestClass object is still in scope"
        
    def __exit__(self, tb1, tb2, tb3):
        print "TestClass.__exit__"
    
    def __del__(self):
        print "TestClass.__del__"

def TestExplodedWith():    
    print "--- Testing exploded with"    
    s_obj = SourceClass()
    print "before with statement"
    mgr = TestClass(s_obj)
    exit = mgr.__exit__  # Not calling it yet
    value = mgr.__enter__()
    exc = True
    try:
        try:
            p = value  # Only if "as VAR" is present
            p.do_work_on()
        except:
            exc = False
            if not exit(*sys.exc_info()):
                raise
    finally:
        if exc:
            exit(None, None, None)
    print "after with statement"
    p.check_if_exists()

def TestUsingWith():
    print "--- Testing with"    
    s_obj = SourceClass()
    print "before with statement"
    with TestClass(s_obj) as p:
        p.do_work_on()
    print "after with statement"
    p.check_if_exists()
    
TestExplodedWith()
TestUsingWith()