简单的一个状态机,哪儿出问题了---yield和return的问题?

简单的一个状态机,哪儿出问题了---yield和return的问题?

代码改自别人。
想实现一个简单状态机,只有两个状态:get_ones和get_more,
math_gen产生的数据流num_stream作为输入;
如果接到的数字小于10,在ONES状态;
否则,在MORE状态。

[Copy to clipboard] [ - ]
CODE:
[ning@58 24_10_2008]$ python state_machine2.py

ONES State:       @ 1.0

为什么从初始ONES状态就不动了?
是yield和return混合用出错了,还是?
弄了好几个小时没弄懂,只好请大家帮忙了

[Copy to clipboard] [ - ]
CODE:
# coding: utf-8

def math_gen(n):
    from math import sin
    while 1:
        yield n
        n = abs(sin(n))*31
def judge(val):
    if 0 val < 30: return 'ONES'
    else: return 'MORE'
def get_ones(iter):
    global cargo
    print "\nONES State:      ",
    if judge(cargo)=='ONES':
        print "@ %2.1f  " % cargo,
        cargo = iter.next()
    return (judge(cargo), cargo)
def get_more(iter):
    global cargo
    print "\nMORE State:      ",
    if judge(cargo)=='MORE':
        print "#%2.1f  " % cargo,
        cargo = iter.next()
    return (judge(cargo), cargo)
def scheduler(gendct, start):
    global cargo
    coroutine = start
    while 1:
        (coroutine, cargo) = gendct[coroutine]
if __name__ == "__main__":
    num_stream = math_gen(1)
    cargo = num_stream.next()
    gendct = {'ONES' : get_ones(num_stream),
              'MORE'  : get_more(num_stream)}
    scheduler(gendct, judge(cargo))

知道了,

[Copy to clipboard] [ - ]
CODE:
    gendct = {'ONES' : get_ones(num_stream),

              'MORE'  : get_more(num_stream)}

出了问题。以为字典里放的是函数,其实是静态的函数返回值。
改成:

[Copy to clipboard] [ - ]
CODE:
    gendct = {'ONES' : get_ones,  

              'MORE'  : get_more}

另外,scheduler相应地变成:

[Copy to clipboard] [ - ]
CODE:
def scheduler(gendct, start):
    global cargo,num_stream
    coroutine = start
    while 1:
        (coroutine, cargo) = gendct[coroutine](num_stream)

就可以了



[Copy to clipboard] [ - ]
CODE:
# coding: utf-8
# t3.py
def math_gen(n):
    from math import sin
    while 1:
        yield n
        n = abs(sin(n))*31
def judge(val):
    if 0 <= val < 30: return 'ONES'
    else: return 'MORE'
def get_ones(iter):
    global cargo
    print "\nONES State:      ",
    while judge(cargo)=='ONES':
        print "@ %2.1f  " % cargo,
        cargo = iter.next()
    return (judge(cargo), cargo)
def get_more(iter):
    global cargo
    print "\nMORE State:      ",
    while judge(cargo)=='MORE':
        print "#%2.1f  " % cargo,
        cargo = iter.next()
    return (judge(cargo), cargo)
def scheduler(gendct, start):
    global cargo,num_stream
    coroutine = start
    while 1:
        (coroutine, cargo) = gendct[coroutine](num_stream)
if __name__ == "__main__":
    num_stream = math_gen(1)
    cargo = num_stream.next()
    gendct = {'ONES' : get_ones, 'MORE'  : get_more}
    scheduler(gendct, judge(cargo))

#把David Mertz的state_machine.py改成自己的t3.py。
#有错误,却总找不到。
#起先以为是while 1,while 1,循环嵌套的毛病,我改成了if,见state_machine2.py。
#还是不行,我又以为return和yield混用的错误,因为这个yield,老是让我感到没底,不知如何修改,
#只好把代码大大重新改过,搞到今天中午(看看state2.py你就知道我改到多少)
#调程序真是件辛苦的事情);
#最后,终于意识到是f()的问题,应该是f,否则传回了静态的函数返回值,而不再是个动态函数了。
#这也是我常常犯的编程错误。

#仔细想想,为何David Mertz的程序可以那样呢--f()。
#就因为他用的是yield,这就使得字典里程序是动态的,因为 yield 总能记住上次访问地点并上下文。#while 1 加上 yield 使那些函数都成了“活的”,并随时听令。
#这可以省下函数每次调用的开销,而且可能如他所说:这样的状态机更自然。



[Copy to clipboard] [ - ]
CODE:
#David Mertz的状态机代码:

#coding: utf-8

from __future__ import generators

import sys

def math_gen(n):    # Iterative function becomes a generator

    from math import sin

    while 1:

        yield n

        n = abs(sin(n))*31

def jump_to(val):

    if    0 <= val < 10: return 'ONES'

    elif 10 <= val < 20: return 'TENS'

    elif 20 <= val < 30: return 'TWENTIES'

    else:                return 'OUT_OF_RANGE'

def get_ones(iter):

    global cargo

    while 1:

        print "\nONES State:      ",

        while jump_to(cargo)=='ONES':

            print "@ %2.1f  " % cargo,

            cargo = iter.next()

        yield (jump_to(cargo), cargo)

def get_tens(iter):

    global cargo

    while 1:

        print "\nTENS State:      ",

        while jump_to(cargo)=='TENS':

            print "#%2.1f  " % cargo,

            cargo = iter.next()

        yield (jump_to(cargo), cargo)

def get_twenties(iter):

    global cargo

    while 1:

        print "\nTWENTIES State:  ",

        while jump_to(cargo)=='TWENTIES':

            print "*%2.1f  " % cargo,

            cargo = iter.next()

        yield (jump_to(cargo), cargo)

def exit(iter):

    jump = raw_input('\n\n[co-routine for jump?] ').upper()

    print "...Jumping into middle of", jump

    yield (jump, iter.next())

    print "\nExiting from exit()..."

    sys.exit()

def scheduler(gendct, start):

    global cargo

    coroutine = start

    while 1:

        (coroutine, cargo) = gendct[coroutine].next()


if __name__ == "__main__":

    num_stream = math_gen(1)

    cargo = num_stream.next()

    gendct = {'ONES'        : get_ones(num_stream),

              'TENS'        : get_tens(num_stream),

              'TWENTIES'    : get_twenties(num_stream),

              'OUT_OF_RANGE': exit(num_stream)         }

    scheduler(gendct, jump_to(cargo))



[Copy to clipboard] [ - ]
CODE:
# coding: utf-8
# 我的state_machine2.py
def math_gen(n):
    from math import sin
    while 1:
        yield n
        n = abs(sin(n+5))*10
def judge(val):
    if val < 5: return 'ONES'
    else: return 'MORE'
def get_ones():
    global cargo
    print "\nONES State:      ",
    print "@ %2.1f  " % cargo,
def get_more():
    global cargo
    print "\nMORE State:      ",
    print "#%2.1f  " % cargo,
if __name__ == "__main__":
    num_stream = math_gen(1)
    cargo = num_stream.next()
    gendct = {'ONES' : get_ones,
              'MORE'  : get_more}
    while 1:
        gendct[judge(cargo)]()
        cargo=num_stream.next()

我觉得没必要用字典,把函数名取得跟字符串一样,然后用getattr会比较好些,便于扩展。


QUOTE:
我觉得没必要用字典,把函数名取得跟字符串一样,然后用getattr会比较好些,便于扩展。

没明白。怎么弄,怎样便于扩展?