state machine and a global variable

T

tuom.larsen

Dear list,
I'm writing very simple state machine library, like this:



_state = None

def set_state(state):
global _state
_state = state

def get_state():
print _surface



but I hate to use global variable. So, please, is there a better way
of doing this? All I want is that a user has to type as little as
possible, like:

from state_machine import *
set_state(3)
get_state()

I.e., nothing like:
import state_machine
my_machine = state_machine.new_machine()
my_machine.set_state(3)
my_machine.get_state()

Thanks, in advance!
 
C

Chris Mellon

Dear list,
I'm writing very simple state machine library, like this:



_state = None

def set_state(state):
global _state
_state = state

def get_state():
print _surface



but I hate to use global variable. So, please, is there a better way
of doing this? All I want is that a user has to type as little as
possible, like:

Yes, don't do it.
from state_machine import *
set_state(3)
get_state()

This isn't a state machine, it's just state
I.e., nothing like:
import state_machine
my_machine = state_machine.new_machine()
my_machine.set_state(3)
my_machine.get_state()

Stop being afraid of objects, especially if your fear is caused by
straw-man C style APIs.

from state_machine import State

state = State()
print state.current_state
state.do_something('sadfsafsad') #does something based on the current state
print state.current_state
 
M

Matimus

Dear list,
I'm writing very simple state machine library, like this:

_state = None

def set_state(state):
global _state
_state = state

def get_state():
print _surface

but I hate to use global variable. So, please, is there a better way
of doing this? All I want is that a user has to type as little as
possible, like:

from state_machine import *
set_state(3)
get_state()

I.e., nothing like:
import state_machine
my_machine = state_machine.new_machine()
my_machine.set_state(3)
my_machine.get_state()

Thanks, in advance!

Personally I _would_ do it the second way. That seems to be the most
appropriate way to do it. However, you can do it the second way and
still get the functionality you desire.


[code in state_machine.py]
class StateMachine(object):
def __init__(self, state=None):
if state is None:
state = "DEFAULT_INIT_STATE"
self._state = state

def get_state(self):
# print self._surface
return self._state

def set_state(self, state):
self._state = state

_sm = StateMachine()
set_state = _sm.set_state
get_state = _sm.get_state
[/code]

Matt
 
T

tuom.larsen

Dear list,
I'm writing very simple state machine library, like this:
_state = None
def set_state(state):
global _state
_state = state
def get_state():
print _surface
but I hate to use global variable. So, please, is there a better way
of doing this? All I want is that a user has to type as little as
possible, like:
from state_machine import *
set_state(3)
get_state()
I.e., nothing like:
import state_machine
my_machine = state_machine.new_machine()
my_machine.set_state(3)
my_machine.get_state()
Thanks, in advance!

Personally I _would_ do it the second way. That seems to be the most
appropriate way to do it. However, you can do it the second way and
still get the functionality you desire.

[code in state_machine.py]
class StateMachine(object):
def __init__(self, state=None):
if state is None:
state = "DEFAULT_INIT_STATE"
self._state = state

def get_state(self):
# print self._surface
return self._state

def set_state(self, state):
self._state = state

_sm = StateMachine()
set_state = _sm.set_state
get_state = _sm.get_state
[/code]

Matt


Thanks a lot! This is precisely what I had on my mind.
 
C

Carl Banks

Dear list,
I'm writing very simple state machine library, like this:

_state = None

def set_state(state):
global _state
_state = state

def get_state():
print _surface

but I hate to use global variable. So, please, is there a better way
of doing this? All I want is that a user has to type as little as
possible, like:

from state_machine import *
set_state(3)
get_state()

I.e., nothing like:
import state_machine
my_machine = state_machine.new_machine()
my_machine.set_state(3)
my_machine.get_state()

Thanks, in advance!

I would recommend you do it the long way, but then provide convenience
functions for users who'd prefer a simplified interface:

def set_state(x):
my_machine.set_state(x)

def set_state():
return my_machine.get_state()


Some users won't want the simplified interface. Really.


Carl Banks
 
B

Bruno Desthuilliers

(e-mail address removed) a écrit :
Dear list,
I'm writing very simple state machine library, like this:



_state = None

def set_state(state):
global _state
_state = state

def get_state():
print _surface

NameError here !-)
but I hate to use global variable.

So, please, is there a better way
of doing this? All I want is that a user has to type as little as
possible, like:

from state_machine import *
set_state(3)
get_state()

I.e., nothing like:
import state_machine
my_machine = state_machine.new_machine()
my_machine.set_state(3)
my_machine.get_state()


A possible solution:

# state_machine.py
class _StateMachine(object):
def __init__(self):
self._state = SomethingHere()
def get_state(self):
return self._state
def set_state(self, xxx):
# etc

_s = _StateMachine()
get_state = _s.get_state()
set_state = _s.set_state()

You still have a global, but at least it's a machine instance, not it's
state !-)

Now the question is: why do you think it's so important for your users
to only see functions ? What's so wrong with:

from state_machine import *
m = get_state_machine()
m.set_state(42)
 
T

tuom.larsen

(e-mail address removed) a écrit :





NameError here !-)








A possible solution:

# state_machine.py
class _StateMachine(object):
def __init__(self):
self._state = SomethingHere()
def get_state(self):
return self._state
def set_state(self, xxx):
# etc

_s = _StateMachine()
get_state = _s.get_state()
set_state = _s.set_state()

I guess you meant without the parentheses:
get_state = _s.get_state
set_state = _s.set_state

You still have a global, but at least it's a machine instance, not it's
state !-)

Now the question is: why do you think it's so important for your users
to only see functions ? What's so wrong with:

from state_machine import *
m = get_state_machine()
m.set_state(42)

Well, I guess I can see the advantages of using the class instances
but ... um ... the world isn't like that! :)

Consider this: how do you add up some numbers?
- "My sum is zero."
- "I add 3 to my sum."
- "I add 2 to my sum."

Or:
- "Three."
- "plus two."

Implicit context, some people call it. Sometimes it's useful to be as
precise as possible ("explicit is better than implict", right?) but
sometimes, it seems to me, it's just more natural not to repeat the
context all over again.

Thoughts?
 
C

Chris Mellon

I guess you meant without the parentheses:
get_state = _s.get_state
set_state = _s.set_state



Well, I guess I can see the advantages of using the class instances
but ... um ... the world isn't like that! :)

Consider this: how do you add up some numbers?
- "My sum is zero."
- "I add 3 to my sum."
- "I add 2 to my sum."

Or:
- "Three."
- "plus two."

Implicit context, some people call it. Sometimes it's useful to be as
precise as possible ("explicit is better than implict", right?) but
sometimes, it seems to me, it's just more natural not to repeat the
context all over again.

You're way too hung up on context when you should be hung up on state.
Implicit state is bad, implicit global state is worse. You've got a
shared global state, with an interface that's designed to dispatch on
and mutate that state. It's basically every bad thing you can imagine
about global state. Using an object means that the state machine is
*local* state. Local state is good, because you've got a way to attach
a name to it, to manipulate it explicitly, and to pass it around to
other places.

Your example presupposes two different use cases anyway, but most
importantly what you're describing with sum is a mutation of local
state (a local name binding), which is a very different thing than
your state machine API.

Honestly, I can't even imagine why you would want to implement a state
machine *library* this way. If you meant "a library that has internal
state" it makes a little more sense - I use an approach kind of like
the one Bruno showed to handle global configuration and logging - but
if you meant "a library for implementing state machines" you're on
totally the wrong track.
 
T

tuom.larsen

You're way too hung up on context when you should be hung up on state.
Implicit state is bad, implicit global state is worse. You've got a
shared global state, with an interface that's designed to dispatch on
and mutate that state. It's basically every bad thing you can imagine
about global state. Using an object means that the state machine is
*local* state. Local state is good, because you've got a way to attach
a name to it, to manipulate it explicitly, and to pass it around to
other places.

Your example presupposes two different use cases anyway, but most
importantly what you're describing with sum is a mutation of local
state (a local name binding), which is a very different thing than
your state machine API.

Honestly, I can't even imagine why you would want to implement a state
machine *library* this way. If you meant "a library that has internal
state" it makes a little more sense - I use an approach kind of like
the one Bruno showed to handle global configuration and logging - but
if you meant "a library for implementing state machines" you're on
totally the wrong track.

Now, I very much *apologize*! I'm very sorry, I meant "a library that
has internal state", instead of "a library for implementing state
machines".

Basically, I agree that often the local state is much more useful. It
just seems to me that for some application it's an overkill. Like say,
for Turtle [1] (no jokes, please :) or PostScript [2].

[1] http://en.wikipedia.org/wiki/Logo_turtle
[2] http://en.wikipedia.org/wiki/PostScript
 
S

Steven D'Aprano

Now the question is: why do you think it's so important for your users
to only see functions ? What's so wrong with:

from state_machine import *
m = get_state_machine()
m.set_state(42)

I can't speak for the "only" part, but it is sometimes really convenient
to have a set of *cough* convenience functions that do the simple stuff
for you. For example:

import random
random.random()

is much nicer for the simple cases than:

import random
prng = random.Random()
prng.random()

with the advantage that you can still instantiate your own instance if
you need/want to.
 
T

tuom.larsen

I can't speak for the "only" part, but it is sometimes really convenient
to have a set of *cough* convenience functions that do the simple stuff
for you. For example:

import random
random.random()

is much nicer for the simple cases than:

import random
prng = random.Random()
prng.random()

with the advantage that you can still instantiate your own instance if
you need/want to.

I agree, completely!

Ok, I think I'm going to provide both the simplified interface and the
class to instantiate. Thanks all!

Now suppose, this class looks like:

class StateMachine(object):
def __init__...
def function0...
def function1...
def function2...
...

up to many. And later in the library I would like to expose the
simplified interface as well:

_machine = StateMachine()
function0 = _machine.function0
function1 = _machine.function1
function2 = _machine.function2
....

Is there a way to do so in a programmatic way? Like:

_machine = StateMachine()
for function in {every function in _machine}:
function = _machine.function

Not that it's difficult to copy-paste some lines, I'm just curious and
maybe it would be a tiny bit easier to maintain the library.
 
S

Steven D'Aprano

On Sat, 15 Dec 2007 01:07:17 -0800, tuom.larsen wrote:

....
later in the library I would like to expose the
simplified interface as well:

_machine = StateMachine()
function0 = _machine.function0
function1 = _machine.function1
function2 = _machine.function2
...

Is there a way to do so in a programmatic way? Like:

_machine = StateMachine()
for function in {every function in _machine}:
function = _machine.function

Not that it's difficult to copy-paste some lines, I'm just curious and
maybe it would be a tiny bit easier to maintain the library.

You can say:

# Untested!
_machine = StateMachine()
from new import instancemethod
for name in _machine.__class__.__dict__:
if name.startswith('_'): continue
obj = getattr(_machine, name)
if type(obj) == instancemethod:
globals()[name] = obj


but that's likely to export a bunch of functions you don't actually want.
A better solution might be to create a class attribute containing the
names you DO want to export, and reject everything else:

class StateMachine(object):
_exportable = ['spam', 'eggs', 'parrot']
# function definitions go here

for name in _machine.__class__.__dict__:
if name in _machine._exportable:
globals()[name] = getattr(_machine, name)
 
M

Michael Sparks

Basically, I agree that often the local state is much more useful. It
just seems to me that for some application it's an overkill. Like say,
for Turtle [1] (no jokes, please :) or PostScript [2].

Sounds also a bit similar to what happens under the hood in Open GL and some
other systems which revolve around display lists. The approach generally
taken there is to recognise that you often have a "current" context which
is being operated on.

A basic version of this might look like this:

file: statemachine_user.py

#!/usr/bin/python

from statemachine import *

context = statemachine()
context2 = statemachine()

set_context(context)
set_state(3)
print get_state()

set_context(context2)
set_state(1)
print get_state()

set_context(context)
print get_state()


file: statemachine.py

#!/usr/bin/python

class statemachine(object):
def __init__(self):
self.state = None
def set_state(self, value):
self.state = value
def get_state(self):
return self.state

context = statemachine()

def set_context(somecontext):
global context
context = somecontext

def set_state(value):
context.set_state(value)

def get_state():
return context.get_state()

A more interesting example which probably relates closer to your example,
and also can be quite useful for interpretting little languages is where
the "states" that get stored are matrices representing transforms and are
used to put objects into a 3D space.

You might in that circumstance want to use your a statemachine more like
this: (this code is untested)

class statemachine(object):
default = None
def __init__(self, **argd):
self.__dict__.update(**argd)
self.state = self.default
def set_state(self, value):
self.state = value
def get_state(self):
return self.state

context = [ statemachine() ] # default context

def push_context(somecontext):
global context
context.append( somecontext )

def pop_context(somecontext):
global context
return context.pop( -1 )

def set_state(value): context[-1].set_state(value)

def get_state(): return context[-1].get_state()

def get_allstates(): return [ x.get_state() for x in context ]

This isn't really quite what the do, but gives a different possible
perspective.


Michael.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,431
Messages
2,571,677
Members
48,796
Latest member
Greg L.

Latest Threads

Top