Re: Python code written in 1998, how to improve/change it?
To provide some feedback I vould like to show the code which works fine for me as a FSM machine. As speed is not the crucial issue for my application, I have decided to use an approach showed in the Skip Montanaro's code. http://orca.mojam.com/~skip/python/fsm.py (it is using dictionary to store state/transition dependencies). Tanks to all for your previous postings. Petr Jakes State machine example, for the pull/push button mentioned earlier in this discussion thread class FSM: '''the states dictionary contains user defined state/transition table in the format: {'start_state': {'event': {'guard': ('action', 'end_state')}}, according to the actual start_state, event and guard combination, the execute method reads the relevant action and end_state from the states dictionary, then executes action and setup end_state ''' def __init__(self): self.states = {} def add(self,start_state, event_trigger,event_guard, action,newstate): add a new state/transition information to the state machine dictionary if self.states.has_key(start_state)== False : self.states[start_state]={} if self.states[start_state].has_key(event_trigger)== False : self.states[start_state][event_trigger]={} if self.states[start_state][event_trigger].has_key(event_guard)== False : self.states[start_state][event_trigger][event_guard]={} self.states[start_state][event_trigger][event_guard]=(action, newstate) def start(self, state): set the start state self.state = state def execute(self, event,guard=None): '''according to the actual start_state, event and guard combination read the relevant action and end_state from the states dictionary, then execute action and setup end_state ''' action, end_state = self.states[self.state][event][guard] if action is not None: apply(action, (self.state, event)) self.state = end_state return '''actions they has to be executed while the event occurs''' def motor_off(state, input): print pushing the switch to the OFF position def motor_on(state, input): print lifting the switch to the ON position fsm = FSM() '''we have to define state/transition table first, wher state transitions are defined as: ('start_state', 'event', 'guard', 'action', 'end_state)''' fsm.add(ON,lift,None,None,ON) fsm.add(ON,push,None,motor_off,OFF) fsm.add(OFF,push,None,None,OFF) fsm.add(OFF,lift,None,motor_on,ON) fsm.start(ON) print start state is, fsm.state events=(push,push,push,lift,lift,push,lift,push,lift,lift,lift,push,lift) for event in (events): fsm.execute(event) print switch is , fsm.state -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
On Wed, 25 Jan 2006 15:50:27 -0600, [EMAIL PROTECTED] wrote: If they need to resume their calculations from where they left off after the last yield. Wolfgang Well, no, independently from that. Wolfgang Just to avoid to inital overhead of the function call. How do you pass in parameters? Consider: def square(x): return x*x vs def square(x) while True: yield x*x How do you get another value of x into the generator? def square(x): ... while True: ... yield x*x ... g = square(2) g generator object at 0x3b9d28 g.next() 4 g.next() 4 g.next(3) Traceback (most recent call last): File stdin, line 1, in module TypeError: expected 0 arguments, got 1 def square(xbox): ... while True: yield xbox[0]*xbox[0] ... xbox = [3] g = square(xbox) g.next() 9 xbox[0]=4 g.next() 16 [g.next() for xbox[0] in xrange(10)] [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] One way to answer your question literally, whatever it may do to your gag reflex ;-) Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
On Tue, 24 Jan 2006 14:58:27 -0600, [EMAIL PROTECTED] wrote: Wolfgang So basically if I want to write a long-running program in Wolfgang Python, it would make sense to code all functions that are Wolfgang likely to be called more than once as generators... If they need to resume their calculations from where they left off after the last yield. Hm, I wonder how (all untested) def foo(x,y): return x**2+y**2 for pair in pairs: print foo(*pair) would compare to def bar(arglist): while True: x,y = arglist yield x**2 + y**2 barargs = [] ibar = bar(barargs).next for barargs[:] in pairs: print ibar() Of course, for simple stuff there's always manual inlining ;-) for x, y in pairs: print x**2, y**2 Hm, bf warning it might be interesting if one could bind arg list items of a generator from the outside, e.g., def gfoo(x, y): while True: yield x**2 + y**2 ifoo = gfoo('dummy','dummy') # or first pair for ifoo.x, ifoo.y in pairs: print ifoo.next() Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
So basically if I want to write a long-running program in Python, it would make sense to code all functions that are likely to be called more than once as generators... This was meant as a question. If they need to resume their calculations from where they left off after the last yield. Well, no, independently from that. Just to avoid to inital overhead of the function call. ? Sincerely, Wolfgang Keller -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
Wolfgang Keller wrote: So basically if I want to write a long-running program in Python, it would make sense to code all functions that are likely to be called more than once as generators... This was meant as a question. If they need to resume their calculations from where they left off after the last yield. Well, no, independently from that. Just to avoid to inital overhead of the function call. ? what makes you think that resuming a generator won't involve function calls ? /F -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
what makes you think that resuming a generator won't involve function calls ? That was not what I wrote. I referred to what Peter Hansen [EMAIL PROTECTED] wrote in [EMAIL PROTECTED]: I believe the more modern approach to this is to use generators in some way, yield each other as the next state. This way you avoid all almost all the function call overhead (the part that takes significant time, which is setting up the stack frame) The way I understand this, resuming a generator causes less overhead than the inital overhead of a function call. Again, I'm just a poor scripting dilettant who's asking questions. Sincerely, Wolfgang Keller -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
Wolfgang Keller wrote: The way I understand this, resuming a generator causes less overhead than the inital overhead of a function call. I don't have Python 2.4 handy, but it doesn't seem to be true in 2.3. I'm not very proficient with generators though, so maybe I'm doing something stupid here... from __future__ import generators def f(): ... return 1 ... def g(): ... while 1: ... yield 1 ... it = g() import time def t(c, n): ... start = time.time() ... for i in xrange(n): ... c() ... print time.time()-start ... t(f,100) 0.277699947357 t(f,100) 0.279093980789 t(f,100) 0.270813941956 t(it.next,100) 0.297060966492 t(it.next,100) 0.263942956924 t(it.next,100) 0.293347120285 For refernce: def t0(c, n): ... start = time.time() ... for i in xrange(n): ... pass ... print time.time()-start ... t0(it.next,100) 0.0523891448975 Maybe the ratio is completely different in a newer Python than 2.3.4 (RH EL3 standard install). Or maybe it's very different if there are plenty of local variables etc in f / g. -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
Wolfgang Keller wrote: what makes you think that resuming a generator won't involve function calls ? That was not what I wrote. I referred to what Peter Hansen [EMAIL PROTECTED] wrote in [EMAIL PROTECTED]: I believe the more modern approach to this is to use generators in some way, yield each other as the next state. This way you avoid all almost all the function call overhead (the part that takes significant time, which is setting up the stack frame) The way I understand this, resuming a generator causes less overhead than the inital overhead of a function call. I think in the spirit of avoiding premature optimization and all things related, now is the time to re-inject the other part of my above-quoted posting, where I also said: Of course, if you have a state machine with many small states each doing a tiny bit of processing and you're still concerned over performance, you probably should be looking into Pysco or Pyrex and avoid making your code really unreadable. -Peter -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
Wolfgang So basically if I want to write a long-running program in Wolfgang Python, it would make sense to code all functions that are Wolfgang likely to be called more than once as generators... Skip If they need to resume their calculations from where they left off Skip after the last yield. Bengt Hm, I wonder how (all untested) ... Bengt would compare to ... I was thinking about things like complex tokenizers. Take a look, for example, at the SpamBayes tokenizer and think about how to implement it without yield. Clearly it can be don (and not all that difficult). Still, I think the generator version would be easier to understand and modify. Skip -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
If they need to resume their calculations from where they left off after the last yield. Wolfgang Well, no, independently from that. Wolfgang Just to avoid to inital overhead of the function call. How do you pass in parameters? Consider: def square(x): return x*x vs def square(x) while True: yield x*x How do you get another value of x into the generator? def square(x): ... while True: ... yield x*x ... g = square(2) g generator object at 0x3b9d28 g.next() 4 g.next() 4 g.next(3) Traceback (most recent call last): File stdin, line 1, in module TypeError: expected 0 arguments, got 1 Skip -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
On Fri, 20 Jan 2006 05:16:57 +0100, Peter Hansen wrote (in article [EMAIL PROTECTED]): I believe the more modern approach to this is to use generators in some way, yield each other as the next state. This way you avoid all almost all the function call overhead (the part that takes significant time, which is setting up the stack frame) and don't have to resort to bytecode hacks for better performance. Dumb question from a endless newbie scripting dilettant: Do you have a reference to a cookbook example for this method? Sidequestion: As I understand it, as a general rule generators are more efficient than functions in any case where the function is called several times, right? So basically if I want to write a long-running program in Python, it would make sense to code all functions that are likely to be called more than once as generators... TIA, Sincerely, Wolfgang Keller -- http://mail.python.org/mailman/listinfo/python-list
Weird generator id() behaviour (was Re: Python code written in 1998, how to improve/change it?)
Wolfgang Keller wrote: On Fri, 20 Jan 2006 05:16:57 +0100, Peter Hansen wrote (in article [EMAIL PROTECTED]): I believe the more modern approach to this is to use generators in some way, yield each other as the next state. This way you avoid all almost all the function call overhead (the part that takes significant time, which is setting up the stack frame) and don't have to resort to bytecode hacks for better performance. Dumb question from a endless newbie scripting dilettant: Do you have a reference to a cookbook example for this method? It turns out that generators are more efficient than the eval function excuting bits of compiled code. About 20-25% faster. However, the generators exhibit some weird behaviour. The included code shows an example using a compile/eval FSM method, and a generator method. Note, in particular, the pattern of ids of the generator objects. I had expected some complications in the ids, but not a repeatable sequence of length 3 after the first generator object. What is going on? Anybody? #!/usr/bin/env python import time s_on = compile(''' print 'on' action = next_action() if action == 'lift': state = s_on elif action == 'push': state = s_off else: state = None ''','','exec') s_off = compile(''' print 'off' action = next_action() if action == 'lift': state = s_on elif action == 'push': state = s_off else: state = None ''','','exec') def g_on(): print on action = next_action() if action == 'lift': yield g_on() elif action == 'push': yield g_off() else: yield None def g_off(): print off action = next_action() if action == 'lift': yield g_on() elif action == 'push': yield g_off() else: yield None def actions(n): import random for i in range(n-1): yield random.choice(['lift','push']) yield None #r = 100 r = 10 next_action = actions(r).next #a = time.clock() while next_action(): pass #z = time.clock() #print action generator:,z-a next_action = actions(r).next #print --- state = s_on # start state #a = time.clock() while state: eval(state) #z = time.clock() #print z-a print --- next_action = actions(r).next s_g_on = g_on() s_g_off = g_off() state = s_g_on #a = time.clock() while state: print id(state) state = state.next() #z = time.clock() #print z-a #Cheers, #Carl. -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
Wolfgang So basically if I want to write a long-running program in Wolfgang Python, it would make sense to code all functions that are Wolfgang likely to be called more than once as generators... If they need to resume their calculations from where they left off after the last yield. Skip -- http://mail.python.org/mailman/listinfo/python-list
Re: Weird generator id() behaviour (was Re: Python code written in 1998, how to improve/change it?)
On Tue, 24 Jan 2006 21:19:26 +0100, Carl Cerecke wrote (in article [EMAIL PROTECTED]): def g_on(): print on action = next_action() if action == 'lift': yield g_on() elif action == 'push': yield g_off() else: yield None def g_off(): print off action = next_action() if action == 'lift': yield g_on() elif action == 'push': yield g_off() else: yield None Amazing. Executable pseudo-code, really. :-) And that's even (run-time) efficient? Tanks a lot, Sincerely, Wolfgang Keller -- http://mail.python.org/mailman/listinfo/python-list
Re: Weird generator id() behaviour (was Re: Python code written in 1998, how to improve/change it?)
Carl Cerecke wrote: It turns out that generators are more efficient than the eval function excuting bits of compiled code. About 20-25% faster. why are you using generators to return things from a function, when you can just return the things ? def f_on(): print on action = next_action() if action == 'lift': return f_on elif action == 'push': return f_off def f_off(): print off action = next_action() if action == 'lift': return f_on elif action == 'push': return f_off state = f_on while state: state = state() /F -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
On Mon, 23 Jan 2006 08:53:59 +1300, Carl Cerecke [EMAIL PROTECTED] wrote: Bengt Richter wrote: On Thu, 19 Jan 2006 23:16:57 -0500, Peter Hansen [EMAIL PROTECTED] wrote: How about something like actions = dict( ...a=compile('print A; state=b','','exec'), ...b=compile('print B; state=c','','exec'), ...c=compile('print C; state=None','','exec') ... ) state = 'a' while state: eval(actions[state]) ... A B C Good idea. But we can eliminate the dictionary lookup: a1 = compile('print A; state=b1','','exec') b1 = compile('print B; state=c1','','exec') c1 = compile('print C; state=None','','exec') state = a1 while state: eval(state) Cool. But unfortunately, neither version works inside a function's local namespace. Using exec instead of eval seems to do it in either context though. Now, how can we get optimized code (i.e., LOAD_FAST vs LOAD_NAME etc in a1 etc) without byte code hackery? Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
Bengt Richter wrote: On Thu, 19 Jan 2006 23:16:57 -0500, Peter Hansen [EMAIL PROTECTED] wrote: How about something like actions = dict( ...a=compile('print A; state=b','','exec'), ...b=compile('print B; state=c','','exec'), ...c=compile('print C; state=None','','exec') ... ) state = 'a' while state: eval(actions[state]) ... A B C Good idea. But we can eliminate the dictionary lookup: a1 = compile('print A; state=b1','','exec') b1 = compile('print B; state=c1','','exec') c1 = compile('print C; state=None','','exec') state = a1 while state: eval(state) Cheers, Carl -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
Sorry, I can't get in. Can you please show me, how to use your approach on the simple push/push ON/OFF button for example please? PS: seriously it is not a homework :) and I feel it like a shame I am asking such a simple questions :( States: ON, OFF Transition event: push, lift transition diagram: = ___ lift | | _V___|__ ,-| ON|__ | || | lift | | push | | '--| OFF |-' || ^ | |___|push -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
Sorry for the typo in my previous posting. Of course it has to be: simple liftt/push ON/OFF button -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
Petr Jakes wrote: Sorry, I can't get in. Can you please show me, how to use your approach on the simple push/push ON/OFF button for example please? PS: seriously it is not a homework :) and I feel it like a shame I am asking such a simple questions :( States: ON, OFF Transition event: push, lift transition diagram: = ___ lift | | _V___|__ ,-| ON|__ | || | lift | | push | | '--| OFF |-' || ^ | |___|push As a starting point, how about: l = 'lift' p = 'push' action_sequence = [l,p,p,l,l,p,l,p,None] next_action = iter(action_sequence).next s_on = compile(''' print 'on' action = next_action() if action == 'lift': state = s_on elif action == 'push': state = s_off else: state = None ''','','exec') s_off = compile(''' print 'off' action = next_action() if action == 'lift': state = s_on elif action == 'push': state = s_off else: state = None ''','','exec') state = s_on # start state while state: eval(state) Cheers, Carl -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
On Thu, 19 Jan 2006 23:16:57 -0500, Peter Hansen [EMAIL PROTECTED] wrote: Carl Cerecke wrote: Carl Cerecke wrote: Ah. Well, my post suggested, as one option, the callables call each other directly. Doh! No I didn't. And they shouldn't. Otherwise the call stack gets out of hand. But I did suggest that each callable representing a state set a global variable, just before it returns, to the callable representing the next state to be called. Still no map required. Just a while loop. In any case, the function call/return is wasted cycles. I believe the more modern approach to this is to use generators in some way, yield each other as the next state. This way you avoid all almost all the function call overhead (the part that takes significant time, which is setting up the stack frame) and don't have to resort to bytecode hacks for better performance. Of course, if you have a state machine with many small states each doing a tiny bit of processing and you're still concerned over performance, you probably should be looking into Pysco or Pyrex and avoid making your code really unreadable. How about something like actions = dict( ...a=compile('print A; state=b','','exec'), ...b=compile('print B; state=c','','exec'), ...c=compile('print C; state=None','','exec') ... ) state = 'a' while state: eval(actions[state]) ... A B C Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
On Fri, 20 Jan 2006 10:27:58 +1300, Carl Cerecke wrote: We want a goto. Unfortunately, this is about the only problem I can think of where gotos are useful. And for reasons well explained elsewhere, gotos are Not Good. I've solved this in a very efficient, but rather unpythonic way. There is a module that does both GOTO and COMEFROM. http://www.entrian.com/goto/ PLEASE don't use it in real code. -- Steven. -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
Petr Jakes wrote: Hello, I am trying to study/understand OOP principles using Python. I have found following code http://tinyurl.com/a4zkn about FSM (finite state machine) on this list, which looks quite useful for my purposes. As this code was posted long time ago (November 1998) I would like to ask if the principles used in this code are still valid in the modern Python and if/how it can be improved (revrited) using futures of current version of Python. Thanks for your comments for a newbie and for your patience. Python places great store on backwards-compatibility. Consequently I'd suggest you try the code out, and report any problems you find back on this list. I'd give you odds it will work. regards Steve -- Steve Holden +44 150 684 7255 +1 800 494 3119 Holden Web LLC www.holdenweb.com PyCon TX 2006 www.python.org/pycon/ -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
Petr Jakes wrote: Hello, I am trying to study/understand OOP principles using Python. I have found following code http://tinyurl.com/a4zkn about FSM (finite state machine) on this list, which looks quite useful for my purposes. As this code was posted long time ago (November 1998) I would like to ask if the principles used in this code are still valid in the modern Python and if/how it can be improved (revrited) using futures of current version of Python. Thanks for your comments for a newbie and for your patience. Petr Jakes Python has no goto. If you think about the possible execution paths through a function, you can represent that as a finite state machine: A FSM is just a graph, and in a function, you get a FSM by treating each statement as a node, and statements that can follow that statement (in the execution order) have a (directed) edge to them (let's ignore exceptions for the moment). So for: a=b if a == 3: z = 0 else: z = 1 print 'spam' we get: (a=b) - (if a == 3) - (z = 0) || (z = 1) - (print 'spam) Now, when we want to emulate a FSM in a function directly (rather than some slower table-driven scheme), we need to use the constructs provided by the language. But simple 'if' statements just don't cut it. We end up with: while state != 'final': if state == 1: # do state 1 stuff here state = 3 elif state == 2: # if cond: state == 1 else: state == 99 elif ... else: # unknown state Problem with this approach is that, on average, you'll have n/2 comparisons of the state variable. What you want is to jump directly from state 1 to state 3 without having to go anywhere else. You want a goto. Another goto-less way is with functions. Each function is a state, which sets a global function variable to the next state-function: def f_state_1(): global func # do state 1 func = f_state_3 def f_state_2(): global func # do state_2 stuff if cond: func = f_state_1 else: func = f_state_99 #etc. func = f_state_1 # start_state while func != None: func() We've eliminated the numerous comparisons, and it is, arguably, more pythonic. But now you have a function-call overhead on each state transition, and any information shared between states has to be in an enclosing scope. We want a goto. Unfortunately, this is about the only problem I can think of where gotos are useful. And for reasons well explained elsewhere, gotos are Not Good. I've solved this in a very efficient, but rather unpythonic way. First, you write (or generate) the code in the first way indicated above. Lots of inefficient 'if' statements in one big function (say, 'fsm'). Then, you write another function (say 'gotoize') which takes fsm as an argument, and *changes the byte code* of the fsm code object to add JUMP_ABSOLUTE bytecodes (i.e. gotos) where the 'state' variable gets reassigned. fsm can then be decorated with gotoize, and you have a very fast (for python) FSM. You are, essentially, doing some (fairly simple) byte-code optimisation. I can dig out the code if you are interested (except it's pretty untidy at the moment. I'd be ashamed to show it in it's current state :-) Ooops. I just reread your post and you claim (or is that plead?) newbie status. Sorry if this is over your head. Hope it helps anyway. Cheers, Carl. -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
On Fri, 20 Jan 2006 10:27:58 +1300, Carl Cerecke [EMAIL PROTECTED] wrote: Petr Jakes wrote: [ a query regarding some 1998 python code that implements a finite state machine ] Python has no goto. Thank goodness! func = f_state_1 # start_state while func != None: func() We've eliminated the numerous comparisons, and it is, arguably, more pythonic ... Agreed. ... now you have a function-call overhead on each state transition ... Have you profiled your code and demonstrated that this particular function call consumes too much time? If you can't stand the overhead of one [extra, parameterless] function call per transition, especially *after* having eliminated the numerous comparisons, then Python may not be the best tool for the job. ... and any information shared between states has to be in an enclosing scope. Well, no, not exactly. Consider an instance of a class that contains its own data (and perhaps some of its own transition functions) but inherits the basic state machine machinery from a finite state machine class (or simply passes itself to a function that implements a finite state machine by examining attributes of its argument). And then there are (or should be!) purists who will claim that if your state machine requires information to be shared between states, then you don't have enough states! ;-) We want a goto. No, we don't. Regards, Dan -- Dan Sommers http://www.tombstonezero.net/dan/ -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
On Fri, 20 Jan 2006 10:27:58 +1300 in comp.lang.python, Carl Cerecke [EMAIL PROTECTED] wrote: [...] Python has no goto. +1 [...] We want a goto. -1 Regards, -=Dave -- Change is inevitable, progress is not. -- http://mail.python.org/mailman/listinfo/python-list
Goto in python - NO! (was Re: Python code written in 1998, how to improve/change it?)
Dave Hansen wrote: On Fri, 20 Jan 2006 10:27:58 +1300 in comp.lang.python, Carl Cerecke [EMAIL PROTECTED] wrote: [...] Python has no goto. +1 [...] We want a goto. -1 I agree entirely. My (rather unclearly made) point was that, for the particular application (FSM), an unrestricted jump is really handy. Not that we want goto in python (Eurg!!) just to make this one case easier. I learnt programming on a Commodore-64 where BASIC programs where required to be liberally sprinkled with gotos (No else. Only one, global, scope. No real functions). I know first hand the pain gotos can inflict. We don't want to go back there. But. They are still really handy for directly implementing a FSM in code! Hence my JUMP_ABSOLUTE bytecode rewrite hack for FSMs. Cheers, Carl. -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
Dan Sommers wrote: On Fri, 20 Jan 2006 10:27:58 +1300, Carl Cerecke [EMAIL PROTECTED] wrote: ... now you have a function-call overhead on each state transition ... Have you profiled your code and demonstrated that this particular function call consumes too much time? Yes. For a parser reading a reasonable size input file, the difference is large enough to be noticeable. If you can't stand the overhead of one [extra, parameterless] function call per transition, especially *after* having eliminated the numerous comparisons, then Python may not be the best tool for the job. Maybe. Except the bytecode *is* quite fast enough. There is just no way of writing python code so the compiler can generate that bytecode. Hence the JUMP_ABSOLUTE bytecode rewrite hack. Cheers, Carl. -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
Thanks for your comments, The mentioned 8 years old code actually works somehow. I am trying to solve very similar problem about FSM as the code in the example does and I do not want to be overburden by the if/elif stuff or by declaring state functions (which IMHO is very similar approach as if/elif). Because of above mentioned, something like FSM-generator looks as a way to go for me (if I can judge with my poor skills). I am using Steve's book Python Web Programming which is actually the best I have found about OOP, classes etc. but as a newbie I am just lost with subclass and mapping attributes etc. while trying to study the code in the example (http://tinyurl.com/a4zkn). All I wanted to know, if, thanks to the improvements in the Python functionality over the years, it is possible to simplify somhow the old code. Otherwise I have to dig through :) Petr Jakes PS: I agree and I do understand the reasons why NOT to use GOTO statements in the code (aka spaghetti code). -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
On 19 Jan 2006 15:53:54 -0800, Petr Jakes [EMAIL PROTECTED] wrote: Thanks for your comments, The mentioned 8 years old code actually works somehow. I am trying to solve very similar problem about FSM as the code in the example does and I do not want to be overburden by the if/elif stuff or by declaring state functions (which IMHO is very similar approach as if/elif). I'm not sure why nobody else in this thread said it, but the most common way of implementing state machines I've seen in Python (unless theres only a couple states you can manage with if/elif) is to use a dict to map states to callables. Because of above mentioned, something like FSM-generator looks as a way to go for me (if I can judge with my poor skills). I am using Steve's book Python Web Programming which is actually the best I have found about OOP, classes etc. but as a newbie I am just lost with subclass and mapping attributes etc. while trying to study the code in the example (http://tinyurl.com/a4zkn). All I wanted to know, if, thanks to the improvements in the Python functionality over the years, it is possible to simplify somhow the old code. Otherwise I have to dig through :) Petr Jakes PS: I agree and I do understand the reasons why NOT to use GOTO statements in the code (aka spaghetti code). -- http://mail.python.org/mailman/listinfo/python-list -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
Chris Mellon wrote: I'm not sure why nobody else in this thread said it, but the most common way of implementing state machines I've seen in Python (unless theres only a couple states you can manage with if/elif) is to use a dict to map states to callables. Ah. Well, my post suggested, as one option, the callables call each other directly. No mapping required. But if you want a dict in there somewhere, feel free to put one in :-) I was complaining about the function-call overhead of this method though, which can be quite significant for a FSM where each state does only a little processing, and there are many transitions - such as in a parser reading in a large file. The byte-code rewriting hack mentioned in a previous post eliminates this overhead. But, I concede, is somewhat ugly. Cheers, Carl. -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
Carl Cerecke wrote: Chris Mellon wrote: I'm not sure why nobody else in this thread said it, but the most common way of implementing state machines I've seen in Python (unless theres only a couple states you can manage with if/elif) is to use a dict to map states to callables. Ah. Well, my post suggested, as one option, the callables call each other directly. Doh! No I didn't. And they shouldn't. Otherwise the call stack gets out of hand. But I did suggest that each callable representing a state set a global variable, just before it returns, to the callable representing the next state to be called. Still no map required. Just a while loop. In any case, the function call/return is wasted cycles. Cheers, Carl. -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
Carl Cerecke wrote: Carl Cerecke wrote: Ah. Well, my post suggested, as one option, the callables call each other directly. Doh! No I didn't. And they shouldn't. Otherwise the call stack gets out of hand. But I did suggest that each callable representing a state set a global variable, just before it returns, to the callable representing the next state to be called. Still no map required. Just a while loop. In any case, the function call/return is wasted cycles. I believe the more modern approach to this is to use generators in some way, yield each other as the next state. This way you avoid all almost all the function call overhead (the part that takes significant time, which is setting up the stack frame) and don't have to resort to bytecode hacks for better performance. Of course, if you have a state machine with many small states each doing a tiny bit of processing and you're still concerned over performance, you probably should be looking into Pysco or Pyrex and avoid making your code really unreadable. -Peter -- http://mail.python.org/mailman/listinfo/python-list
Re: Python code written in 1998, how to improve/change it?
Petr Hello, I am trying to study/understand OOP principles using Petr Python. I have found following code http://tinyurl.com/a4zkn about Petr FSM (finite state machine) on this list, which looks quite useful Petr for my purposes. As this code was posted long time ago (November Petr 1998) I would like to ask if the principles used in this code are Petr still valid in the modern Python and if/how it can be improved Petr (revrited) using futures of current version of Python. A more up-to-date version of my finite state machine class (referenced in the 1998 post you refer to) is available here: http://orca.mojam.com/~skip/python/fsm.py It's still in use, though I haven't written anything new with it in a year or so. Skip -- http://mail.python.org/mailman/listinfo/python-list