1つの実用的な例を見てみましょう。
ゲームのメニューナビゲーションをプログラミングしているとしましょう。メニュー項目ごとに保存したい
- エントリの名前
- それを押した後に到達する他のメニュー。
- メニューを押したときに実行されるアクション。
メニュー項目が押されると、メニュー項目アクションがアクティブになり、次のメニューに移動します。したがって、メニューは次のような辞書の単純なリストになります。
options,start_menu,about = [],[],[]
def do_nothing(): pass
about += [
{'name':"copyright by...",'action':None,'menu':about},
{'name':"back",'action':do_nothing,'menu':start_menu}
]
options += [
{'name':"volume up",'action':volumeUp,'menu':options},
{'name':"save",'action':save,'menu':start_menu},
{'name':"back without save",'action':do_nothing,'menu':start_menu}
]
start_menu += [
{'name':"Exit",'action':f,'menu':None}, # no next menu since we quite
{'name':"Options",'action':do_nothing,'menu':options},
{'name':"About",'action':do_nothing,'menu':about}
]
どのようabout
に循環的であるかを見てください:
>>> print about
[{'action': None, 'menu': [...], 'name': 'copyright by...'},#etc.
# see the ellipsis (...)
メニュー項目が押されると、次のクリック機能が発行されます。
def menu_item_pressed(item):
log("menu item '%s' pressed" % item['name'])
item['action']()
set_next_menu(item['menu'])
さて、循環データ構造がなければ、それ自体を指すメニュー項目を作成することはできません。たとえば、ボリュームアップ機能を押した後、オプションメニューを終了する必要があります。
循環データ構造が不可能な場合は、自分で実装する必要があります。たとえば、メニュー項目は次のようになります。
class SelfReferenceMarkerClass: pass
#singleton global marker for self reference
SelfReferenceMarker = SelfReferenceMarkerClass()
about += [
{'name':"copyright by...",'action':None,'menu':srm},
{'name':"back",'action':do_nothing,'menu':start_menu}
]
menu_item_pressed
関数は次のようになります。
def menu_item_pressed(item):
item['action']()
if (item['menu'] == SelfReferenceMarker):
set_next_menu(get_previous_menu())
else:
set_next_menu(item['menu'])
最初の例は少し良いですが、そうです、自己参照をサポートしないことは、この制限を簡単に克服できるので、それほど大したことではありません。
メニューの例は、自己参照のあるグラフのようなもので、頂点ポインターのリストごとにグラフを格納します(すべての頂点は他の頂点へのポインターのリストです)。この例では、セルフエッジ(それ自体を指す頂点)が必要だったため、Pythonによる循環データ構造のサポートが役立ちます。