script uses up all memory

Marko Rauhamaa marko at pacujo.net
Thu Mar 6 19:31:13 EST 2014


Chris Angelico <rosuav at gmail.com>:

> On Fri, Mar 7, 2014 at 10:53 AM, Marko Rauhamaa <marko at pacujo.net> wrote:
>>    class MyStateMachine:
>>        def __init__(self):
>>            sm = self
>>
>>            class IDLE:
>>                def ding(self):
>>                    sm.open_door()
>>                    sm.state = AT_DOOR()
>
> Yeah, that's an extremely unusual way to do things. Why keep on
> instantiating objects when you could just reference functions?

That's not crucial. Even if the state objects were instantiated and
inner classes not used, you'd get the same circularity:

   class State:
       def __init__(self, sm):
           self.sm = sm

   class Idle(State):
       def ding(self):
           self.sm.open_door()
           self.sm.state = self.sm.AT_DOOR

   class AtDoor(state):
       ...

   class MyStateMachine:
       def __init__(self):
           self.IDLE = Idle(self)
           self.AT_DOOR = AtDoor(self)
           ...
           self.state = self.IDLE


The closure style is more concise and to the point and might perform no
worse.

> Nope; certainly not with closures. I do a whole lot of event-driven
> programming (usually in Pike rather than Python, but they work the
> same way in this), and there's no reference loop. Properly-done
> event-driven programming should have two basic states: a reference
> from some invisible thing that can trigger the event (eg a GUI widget)
> to a callable, and a reference from that callable to its state. Once
> the trigger is gone, the callable is dropped, its state is dropped,
> and everything's cleaned up. You don't usually need a reference inside
> the function to that function.

I'm more familiar with networking. If you need a timer, you need to be
able to start it so you need a reference to it. Ok, maybe you
instantiate a new timer each time, but you may need to cancel the timer
so starting the timer gives you a ticket you can use for canceling.
Similarly, you need a socket (wrapper) to signal an I/O state change,
and you also need to be able to close the socket at a bare minimum.

The task scheduling service (asyncio has one) collects thunks that refer
to your objects and your objects have a reference to the task scheduling
service to be able to schedule new tasks.

> Don't forget, a closure need only hang onto the things it actually
> uses. It doesn't need all its locals.

More importantly, there's nothing bad in circularity. No need to avoid
it. No need to cut cords.


Marko



More information about the Python-list mailing list