前回: リスト内包表記で改行入れるとスマートじゃん - 0xf
ちょっとローカルで立てた gpt-oss とお話しするCUIを書いていた。で、LangGraph 経由で Ollama から戻ってくるメッセージを処理するところでどうしてもループが重なってインデントが深くなってしまうので、リスト内包で書けないかな、と思ったわけです。
for events in graph.stream({"messages": [HumanMessage(content=user_input)]}): for name, event in events.items(): if name == "agent": for message in event["messages"]: if message.content: print(f"{name}: {message.content}") elif name == "tools": print(" ... tool calling ...")
これが、リスト内包と match だとこう書ける!!!! すごい、python っぽくない。
for name, message in ( (name, message) for events in graph.stream({"messages": [HumanMessage(content=user_input)]}) for name, event in events.items() for message in event.get("messages",[]) if name == "tools" or message.content ): match name: case "agent": print(f"{name}: {message.content}") case "tools": print(" ... tool calling ...") case _: pass
いや、どうかな...高機能な flatten くらいの気持ちだったけど、たぶん読みづらいですね。確かにインデントは浅くなってるんだけど行数は減ってないし for の数は増えているからなあ。
リスト内包で forがネストするときの順番がいつもわかんなくなるんですよね。インデントがないだけで普通の for と一緒だと思えばいいのですが。ラインデバッグがやりづらくなるなどのネガティブ面の方が強いだろうか。ひとまとまりのデータ抽出処理なのだという、強い意思表示はできます。
for の中から if 文を剥がすことも可能ですが、ちょっとごちゃっとする気がする。python は matchが文なので内包表記に含めることができない。惜しい..。
for name, content in ( (name, "tool calling..." if name == "tools" else message.content) for events in graph.stream({"messages": [HumanMessage(content=user_input)]}) for name, event in events.items() for message in event.get("messages",[]) if message.content or name == "tools" ): print(f"{name}: {content}")