こんにちは、超久しぶりに記事を書く六角レンチです。
今日は標準ライブラリを見ていたら使えそうなライブラリを見つけたので、紹介したいと思います。
紹介するやつ
簡単に言うと、対話型UIのフレームワークです。
iwctlみたいな感じのものが作れそう
今回はこれを使って、マクドナルドの略称か判別する対話型UIアプリを作ろうと思います(謎)
略称か判別する関数
マクドナルドの略称か判別する関数を作ります。
といっても昔作ったので、コピペしてきました
def is_macdonald_ryakusyou(ryakusyou: str) -> bool:
MACDONALD = "マクドナルド"
if type(ryakusyou) is not str:
print("文字列ちゃうやんけ")
elif len(ryakusyou) == 0:
print("空文字やんけ")
else:
index = 0
for i in MACDONALD:
if ryakusyou[index] == i:
index += 1
if index == len(ryakusyou):
break
else:
return False
return True
対話型UI化
判別する関数が動くことを確認できたので、いよいよ対話型UIを作っていきます
from cmd import Cmd
class MacdonaldCheckShell(Cmd):
def do_macdonaldcheck(self, ryakusyou: str) -> None:
"""マクドナルドの略称か判別するコマンド"""
MACDONALD = "マクドナルド"
if type(ryakusyou) is not str:
self.error("文字列ちゃうやんけ")
elif len(ryakusyou) == 0:
self.error("空文字やんけ")
else:
index = 0
for i in MACDONALD:
if ryakusyou[index] == i:
index += 1
if index == len(ryakusyou):
break
else:
print(f"略称: [{ryakusyou}]は不正。")
return
print(f"略称: [{ryakusyou}]は正しい。")
def do_exit(self, _: str) -> bool:
"""終了するコマンド"""
print("exit...")
return True
@staticmethod
def error(*text: str) -> None:
print("Error: " + "\n".join(text))
if __name__ == "__main__":
MacdonaldCheckShell().cmdloop()
staticmethodのerrorはエラー表示をするために作った
コマンドの作り方は関数名をdo_{コマンド名}
って感じにすることでできる
また、コマンドの関数の返り値としてTrue
を返すことで対話型UIを終了させることが可能
docstring(関数の下に書いてる"""
で囲んでる文字列)がヘルプメッセージになる
関数の引数はコマンドの引数が入る...と思ったら入力された文字のコマンド以降の部分が入る。
例えば、test honi hoya
が入力されるとdo_test
関数の第一引数にhoni hoya
の文字列が入ってくる
前後の空白文字は消されるので入力された文字.lstrip(コマンド名).strip()
された物が引数に来ると考えるといいかも(ちょっと使いにくいような...)
実行してみた
help コマンド名
でヘルプメッセージを表示できる
Tabキーによるコマンド推測、上下矢印キーのコマンド履歴も使用可能だった(すごい)
改良
対話型UIにする事ができたものの、一つバグがある。
それは、「マック」が略称として判別されないということである。
「マック」の略称は、私個人の意見としては正しくないと考えているが(思想強め) 公式でも「朝マック」や「マックシェイク 」という名称があるので、略称として正しくなければならない。
(というかマックの名前がついた商品はあるのに、マクドの名前がついた商品ないんだな...)
そこで、マクドナルドの略称を追加、削除するコマンドを追加して対応する。
改良したプログラムがこちら
from cmd import Cmd
from typing import Literal
class MacdonaldCheckShell(Cmd):
def __init__(self) -> None:
super().__init__()
self.macdonald_strings: set[str] = set()
def do_macdonaldcheck(self, ryakusyou: str) -> None:
"""マクドナルドの略称か判別するコマンド"""
if ryakusyou in self.macdonald_strings:
print(f"略称: [{ryakusyou}]は正しい。")
return
MACDONALD = "マクドナルド"
if type(ryakusyou) is not str:
self.error("文字列ちゃうやんけ")
elif len(ryakusyou) == 0:
self.error("空文字やんけ")
else:
index = 0
for i in MACDONALD:
if ryakusyou[index] == i:
index += 1
if index == len(ryakusyou):
break
else:
print(f"略称: [{ryakusyou}]は不正。")
return
print(f"略称: [{ryakusyou}]は正しい。")
def do_macdonaldadd(self, ryakusyou: str) -> None:
"""マクドナルドの略称を追加するコマンド"""
if ryakusyou in self.macdonald_strings:
self.error("もう略称になっています")
else:
self.macdonald_strings.add(ryakusyou)
print("追加完了")
def do_macdonalddelete(self, ryakusyou: str) -> None:
"""マクドナルドの略称を削除するコマンド"""
if ryakusyou not in self.macdonald_strings:
self.error("略称に登録されていません")
else:
self.macdonald_strings.discard(ryakusyou)
print("削除完了")
def do_macdonaldstrings(self, _: str) -> None:
"""マクドナルドの略称に追加された文字を表示するコマンド"""
if len(self.macdonald_strings) == 0:
print("マクドナルドの略称は登録されていません")
else:
print("マクドナルドの略称")
for i in self.macdonald_strings:
print(f"|{i}")
def do_exit(self, _: str) -> Literal[True]:
"""終了するコマンド"""
print("exit...")
return True
@staticmethod
def error(*text: str) -> None:
print("Error: " + "\n".join(text))
if __name__ == "__main__":
MacdonaldCheckShell().cmdloop()
新たにmacdonaldadd
、macdonalddel
、macdonaldstrings
コマンドを追加
それぞれ追加
、削除
、確認
ができるコマンドになっている
実際にマック
を追加してみると...
さらにいろいろ...
公式ドキュメントを見た感じ、変数を変えたりすることで挙動や見た目を変えることが可能らしい。
(難しく言うと、変数をオーバーライドする。)
ということでいろいろ試してみた
intro
対話型UIに入ったときいれた文字を出力させることができる
マクドナルド判別アプリへようこそ!
の文字列を入れてみた
prompt
入力する場所の左の(Cmd)
の部分の文字列を変更することができる
CUIで対話型なので>>>
のほうが見やすいかも
他にもヘルプメッセージ関係でいじれそうなところあるけど、このプログラムにはこの2つで十分かも
完成
from cmd import Cmd
from typing import Literal
class MacdonaldCheckShell(Cmd):
intro = "マクドナルド判別アプリへようこそ!"
prompt = ">>> "
def __init__(self) -> None:
super().__init__()
self.macdonald_strings: set[str] = set()
def do_macdonaldcheck(self, ryakusyou: str) -> None:
"""マクドナルドの略称か判別するコマンド"""
if ryakusyou in self.macdonald_strings:
print(f"略称: [{ryakusyou}]は正しい。")
return
MACDONALD = "マクドナルド"
if type(ryakusyou) is not str:
self.error("文字列ちゃうやんけ")
elif len(ryakusyou) == 0:
self.error("空文字やんけ")
else:
index = 0
for i in MACDONALD:
if ryakusyou[index] == i:
index += 1
if index == len(ryakusyou):
break
else:
print(f"略称: [{ryakusyou}]は不正。")
return
print(f"略称: [{ryakusyou}]は正しい。")
def do_macdonaldadd(self, ryakusyou: str) -> None:
"""マクドナルドの略称を追加するコマンド"""
if ryakusyou in self.macdonald_strings:
self.error("もう略称になっています")
else:
self.macdonald_strings.add(ryakusyou)
print("追加完了")
def do_macdonalddelete(self, ryakusyou: str) -> None:
"""マクドナルドの略称を削除するコマンド"""
if ryakusyou not in self.macdonald_strings:
self.error("略称に登録されていません")
else:
self.macdonald_strings.discard(ryakusyou)
print("削除完了")
def do_macdonaldstrings(self, _: str) -> None:
"""マクドナルドの略称に追加された文字を表示するコマンド"""
if len(self.macdonald_strings) == 0:
print("マクドナルドの略称は登録されていません")
else:
print("マクドナルドの略称")
for i in self.macdonald_strings:
print(f"|{i}")
def do_exit(self, _: str) -> Literal[True]:
"""終了するコマンド"""
print("exit...")
return True
@staticmethod
def error(*text: str) -> None:
print("Error: " + "\n".join(text))
if __name__ == "__main__":
MacdonaldCheckShell().cmdloop()
傍から見てわかりやすくかけるようになっていると思う
実行結果
おわり
標準ライブラリにこんな便利なものがあるとは...
他にも便利そうなライブラリがあったので使いたいです
簡単にクラスを使ってアプリを作ることができるので、プログラミング初心者にもおすすめできるかも
クラスの使い方を知れるし、対話型UIの部分を作らなくても良いのがおすすめポイント
あと個人的にオーバーライドは何が良いんだ?と考えていたので驚いた
こういう使い方もあるんだなぁって感じで勉強になった