🧮

Python x Streamlitでミニ電卓アプリ

に公開

🧮 【プログラミング初心者向け】Streamlit で作るミニ電卓アプリ

プログラミングで何かを作ってみたいけれど、何から始めればいいかわからない...そんな方に朗報です!今回は、Python の Streamlit を使って、実際に使える電卓アプリを作成します。

計算機能だけでなく、履歴保存や統計情報まで含む本格的なアプリを、初心者でも理解できるように詳しく解説していきます。

🌟 この記事を読めば...

オーストラリアの豆知識も交えながら楽しくコーディングできます 🦘

この記事では、単なる電卓アプリを作るだけでなく、計算結果をオーストラリアの数字と比較して面白い表現を生成する機能も実装します。例えば:

  • 計算結果がシドニーの人口より多いかチェック
  • カンガルーの数と比較して面白い表現を生成
  • ランダムなオーストラリアの豆知識も表示

プログラミングを楽しみながら知識を身に着けましょう!

😒 本当に初心者でも作れるの?

はい!Streamlit を使えば、HTML や CSS の知識がなくても、Python の基本文法だけで美しい Web アプリが作れます。今回の電卓アプリは、プログラミングの基本概念(入力・処理・出力、条件分岐、エラー処理)を学びながら、実際に使えるアプリを作成できます!

📁 フォルダとファイルの作成

まず、プロジェクト用のフォルダとファイルを作成しましょう。

1. フォルダの作成

デスクトップや任意の場所に「calculator-project」という名前のフォルダを作成してください。

  • Windows: 右クリック → 新規作成 → フォルダ
  • Mac: 右クリック → 新規フォルダ
  • フォルダ名: calculator-project

2. ファイルの作成

  • calculator.py - メインの Python ファイル
  • requirements.txt - 必要なライブラリの一覧

3. フォルダ構造

calculator-project/
├── calculator.py
└── requirements.txt

4. 必要なライブラリをインストール

まず、requirements.txtファイルに以下を書きます:

streamlit>=1.28.0
pandas>=2.0.0
numpy>=1.24.0
random>=3.12.0

これで、プロジェクトの準備が整いました!

🧮 ミニ電卓アプリを作ってみよう

さっそく、calculator.py にコードを書いていきましょう!

📱 アプリの基本設定

まずは、アプリの基本設定から始めます。

import streamlit as st  # Webアプリ作成用
import pandas as pd     # データ処理用
import numpy as np      # 数値計算用
import random  # ランダム選択用

# ページ設定
st.set_page_config(
    page_title="ミニ電卓アプリ",  # ブラウザのタブに表示されるタイトル
    page_icon="🧮",              # ブラウザのタブに表示されるアイコン
    layout="centered"            # レイアウトを中央寄せに設定
)

# タイトルとヘッダー
st.title("🧮 ミニ電卓アプリ")  # メインタイトル
st.markdown("---")  # 区切り線
st.markdown("### 計算してオーストラリアの数字と比較しよう!")  # サブタイトル

cursor のターミナルで以下のコマンドを実行して画面表示を確認しましょう!

python -m streamlit run calculator.py

📊 入力部分の作成

次に、ユーザーが数字を入力できる部分とオーストラリアのデータを準備します。

# ===== 計算履歴を保存する仕組み =====
# session_stateは、ページを更新してもデータを保持する仕組み
if 'calculation_history' not in st.session_state:
    st.session_state.calculation_history = []  # 空のリストで初期化

# ===== オーストラリアの基本データ(比較用) =====
australia_data = {
    "人口": 25687041,
    "面積": 7692024,
    "カンガルー数": 50000000,
    "コアラ数": 80000,
    "シドニー人口": 5312163,
    "メルボルン人口": 5078193,
    "エアーズロック高さ": 348,
    "グレートバリアリーフ長さ": 2300,
}

# ===== メインの計算部分(2列レイアウト) =====
col1, col2 = st.columns(2)  # 画面を2つの列に分割

# 左側の列:数字入力部分
with col1:
    st.subheader("📊 数字を入力")
    num1 = st.number_input("1つ目の数字", value=0)  # 1つ目の数字入力欄
    num2 = st.number_input("2つ目の数字", value=0)  # 2つ目の数字入力欄

# 右側の列:計算方法選択部分
with col2:
    st.subheader("⚡ 計算方法を選択")
    operation = st.radio(
        "どの計算をしますか?",  # ラジオボタンのタイトル
        ("➕ 足し算", "➖ 引き算", "✖️ かけ算", "➗ わり算")  # 選択肢
    )

画面が以下のようになるはずです!

🚀 計算処理の実装

計算を実行するボタンと処理部分を作成します。オーストラリアの数字と比較する機能も含めます。

# ===== 計算実行ボタンと処理 =====
if st.button("🚀 計算実行!", type="primary"):  # ボタンを作成。type="primary"でボタンを青色表示。ボタンが押された時の処理を以下
    try:  # エラーが発生する可能性がある処理はtry囲む
        # ===== 計算処理(選択された演算に応じて分岐) =====
        if operation == "➕ 足し算":  # もし"➕ 足し算"が選択された場合
            result = num1 + num2  # 足し算の実行
            # 結果をオーストラリアの数字と比較して事実を生成
            if result > australia_data["シドニー人口"]:
                # {result:.0f} は小数点以下を切り捨てて整数表示。
                # {australia_data['シドニー人口']:,} は数値をカンマ区切りで表示する
                fact = f"🏙️ この数字({result:.0f})は、シドニーの全人口({australia_data['シドニー人口']:,}人)より多い!"
            elif result > australia_data["メルボルン人口"]:
                fact = f"🏙️ この数字({result:.0f})は、メルボルンの全人口({australia_data['メルボルン人口']:,}人)くらい!"
            elif result > 100000:
                fact = f"🏘️ この数字({result:.0f})は、中規模都市の人口規模です!"
            else:
                fact = f"🏠 この数字({result:.0f})は、比較が難しい数字です。ごめんなさい!"

        elif operation == "➖ 引き算":  # もし"➖ 引き算"が選択された場合
            result = num1 - num2  # 引き算の実行
            # abs()関数:負の数を正の数に変換
            if abs(result) > australia_data["グレートバリアリーフ長さ"]:
                fact = f"🐠 この数字({result:.0f})は、グレートバリアリーフ({australia_data['グレートバリアリーフ長さ']}km)より長い距離!"
            elif abs(result) > australia_data["ウルル高さ"]:
                fact = f"🏔️ この数字({result:.0f})は、ウルル({australia_data['ウルル高さ']}m)より高い!"
            elif abs(result) > 100:
                fact = f"🏢 この数字({result:.0f})は、高層ビル級の高さ!"
            else:
                fact = f"🏠 この数字({result:.0f})は、何と表現したらいいか。。。"

        elif operation == "✖️ かけ算":  # もし"✖️ かけ算"が選択された場合
            result = num1 * num2  # かけ算の実行
            if result > australia_data["カンガルー数"]:
                fact = f"🦘 この数字({result:.0f})は、オーストラリア全体のカンガルー({australia_data['カンガルー数']:,}匹)より多い!"
            elif result > australia_data["コアラ数"]:
                fact = f"🐨 この数字({result:.0f})は、オーストラリア全体のコアラ({australia_data['コアラ数']:,}匹)より多い!"
            elif result > 1000:
                fact = f"🐑 この数字({result:.0f})は、羊の群れサイズ!"
            else:
                fact = f"🦘 この数字({result:.0f})は、小さなカンガルーファミリーくらい!ってことで!"

        elif operation == "➗ わり算":  # もし"➗ わり算"が選択された場合
            if num2 == 0:  # ゼロ割りのチェック
                st.error("❌ ゼロで割ることはできません!")
            result = num1 / num2  # わり算の実行
            if result > 100:
                # {result:.1f} は小数点以下1桁まで表示。
                fact = f"⚡ この数字({result:.1f})は、雷の速度級!(約{result:.0f}km/h)"
            elif result > 80:
                fact = f"🚗 この数字({result:.1f})は、高速道路の速度くらい!(約{result:.0f}km/h)"
            elif result > 10:
                fact = f"🚲 この数字({result:.1f})は、サイクリング速度!(約{result:.0f}km/h)"
            else:
                fact = f"🚶 この数字({result:.1f})は、歩く速度くらい!(約{result:.0f}km/h)"

📝 プログラミング構文の詳細説明:

  • try-except文 - エラーが発生する可能性がある処理を安全に実行

    • try: - エラーが発生する可能性があるコードを囲む
    • except: - エラーが発生した時の処理を記述
    • 今回はゼロで割ることはできないため、try-except を使用しエラーを防ぐ
    • アプリが動かなくならずに、ユーザーフレンドリーなエラーメッセージを表示
  • if-elif-else文 - 条件に応じて処理を分岐

    • if 条件1: - 最初の条件が真の場合の処理
    • elif 条件2: - 条件 1 が偽で、条件 2 が真の場合の処理
    • else: - すべての条件が偽の場合の処理
    • 今回は計算方法(足し算、引き算、かけ算、わり算)に応じて異なる処理を実行
    • 計算結果の大きさに応じて異なるメッセージを表示

💡 条件分岐をわかりやすく図解化

📝 書式指定の詳細説明:

  • {result:.0f} - 小数点以下を切り捨てて整数表示

    • 例:123.456123
    • .0fの意味:小数点以下 0 桁で浮動小数点形式
  • 小数点以下 1 桁まで表示したい場合、以下のようにする
    {result:.1f}

    • 例:123.456123.5
    • 例:100.0100.0
  • {australia_data['シドニー人口']:,} - 数値をカンマ区切りで表示

    • 例:53121635,312,163
    • :,の意味:千の位ごとにカンマを挿入

✨ 結果表示の実装

計算結果を美しく表示し、オーストラリアの豆知識も一緒に表示する部分を作成します。

        # 結果表示
        st.markdown("---")  # 区切り線を表示
        st.subheader("✨ 計算結果")  # サブヘッダーを表示
        st.success(f"🎉 答え: **{result:.2f}**")  # 計算結果を表示

        # 🚀 計算処理の実装でfactという変数に入れたメッセージを表示
        st.info(f"💡 {fact}")

        # 複数のオーストラリアの事実を格納したリスト
        facts = [
            "🦘 オーストラリアには人間よりカンガルーの方が多い!",
            "🐨 コアラは1日に18-22時間も眠る!",
            "🌊 オーストラリアの海岸線は35,877km!",
            "🏜️ オーストラリアの約70%は砂漠!",
            "🏖️ オーストラリアには10,000以上のビーチがある!"
        ]
        st.write("ランダムオーストラリア豆知識")  # テキストを表示
        # random.choice()関数:リストからランダムに1つの要素を選択
        st.write(f"🎯 {random.choice(facts)}")

        # 履歴に追加
        # 演算子の記号を正しく表示するためのマッピング
        # 辞書:キーと値のペアでデータを格納するデータ構造
        symbol_map = {
            "➕ 足し算": "+",    # キー:"➕ 足し算"、値:"+"
            "➖ 引き算": "-",    # キー:"➖ 引き算"、値:"-"
            "✖️ かけ算": "×",   # キー:"✖️ かけ算"、値:"×"
            "➗ わり算": "÷"     # キー:"➗ わり算"、値:"÷"
        }
        # get()メソッド:辞書(symbol_map)から値を取得
        symbol = symbol_map.get(operation, "?")  # operationキーに対応する値を取得、なければ"?"を返す
        # session_state:ページを更新してもデータを保持するStreamlitの機能
        # append()メソッド:リストの末尾に要素を追加
        st.session_state.calculation_history.append(f"{num1} {symbol} {num2} = {result:.2f}")

        st.toast("🎵 計算完了!")  # 一時的な通知メッセージを表示
    except Exception as e:  # エラーが発生した場合の処理
        st.error(f"❌ エラーが発生しました: {str(e)}")

📝 結果表示で使用する構文の詳細説明:

  • st.success()、info()、error() - 文を色つきで表示
    success👉 緑
    info 👉 青
    error 👉 赤

  • random.choice()関数 - リストからランダムに 1 つの要素を選択

    • 例:
      lists = ["りんご", "みかん", "もも", "レモン"]
      random.choice(lists)  # → "みかん"
      
  • マッピング(辞書) - キーと値の対応関係を定義

    • 例:symbol_map = {"🌞 晴れ": "sunny", "🌧️ 雨": "rainy", "⛄ 雪": "snowy"}
    • キー:"🌞 晴れ"、値:"sunny"
    • キー:"🌧️ 雨"、値:"rainy"
    • キー:"⛄ 雪"、値:"snowy"
  • get()メソッド - 辞書から安全に値を取得

    • 例:symbol_map.get(operation, "?")
    • キーが存在しない場合でもエラーにならず、デフォルト値を返す
  • append()メソッド - リストの末尾に要素を追加

    • 例:
      fruits = ["りんご", "みかん"]  # 最初のリスト
      fruits.append("ぶどう")        # "ぶどう"を追加
      print(fruits)                  # ["りんご", "みかん", "ぶどう"]
      
  • except Exception as e - エラーハンドリング

    • Exception:すべてのエラーの種類をキャッチ
    • as e:エラー情報を変数eに格納
    • str(e):エラーメッセージを文字列として取得
    • 予期しないエラーが発生してもアプリが停止しないようにする

問題なく計算処理できているか、画面を動かして確認しましょう!

📊 履歴表示機能

計算履歴をテーブル形式で表示する機能を実装します。

# 履歴表示
st.markdown("---")  # 区切り線を表示
st.subheader("📜 計算履歴")  # サブヘッダーを表示

# 計算結果の統計情報
if st.session_state.calculation_history:  # 履歴が空でない場合(True)
    # 履歴から計算結果の数値のみを抽出
    # calc.split('=')[1]:文字列を'='で分割し、2番目の要素(結果部分)を取得
    # .strip():文字列の前後の空白を削除
    # float():文字列を浮動小数点数に変換
    results = [float(calc.split('=')[1].strip()) for calc in st.session_state.calculation_history]
    # np.mean()関数:配列の平均値を計算
    st.info(f"📊 計算履歴の平均: {np.mean(results):.2f}")

    # pd.DataFrame():リストからDataFrameを作成
    # columns=['計算履歴']:列名を指定
    df = pd.DataFrame(st.session_state.calculation_history, columns=['計算履歴'])
    # st.dataframe():dfをテーブル形式で表示
    # use_container_width=True:幅いっぱいに表示
    st.dataframe(df, use_container_width=True)
else:  # 履歴が空の場合(False)
    st.write("まだ計算していません。上で計算してみましょう!")

# 履歴クリアボタン
# 履歴が存在する場合のみクリアボタンを表示
if st.session_state.calculation_history:  # 履歴が存在する場合(True)
    if st.button("🗑️ 履歴をクリア"):  # ボタンを作成、ボタンが押された場合
        st.session_state.calculation_history = []  # 履歴を空のリストに初期化
        st.rerun()  # ページを再読み込みして表示を更新

📝 履歴処理で使用する関数の詳細説明:

  • float()関数 - 文字列を、小数点を含む数値(浮動小数点数)に変換。整数や小数の文字列を計算可能な数値に変換できます

    • なぜ使う? 文字列の"5"は計算できないが、数値の 5.0 は計算できる

    • 例:

      # 文字列から数値への変換
      text1 = "3.14"           # ダブルクォートで囲っているので文字列
      number1 = float(text1)   # → 3.14 (数値型)
      
      text2 = "100"            # ダブルクォートで囲っているので文字列
      number2 = float(text2)   # → 100.0 (数値型)
      
      # 数値になったので計算可能
      print(number1 + number2)  # → 103.14
      
  • strip()メソッド - 文字列の前後の空白を削除

    • 例:
      text = "  こんにちは  "
      cleaned = text.strip()  # → "こんにちは"
      print(f"'{cleaned}'")   # → 'こんにちは'
      
  • split('=')[1] - 文字列を分割して特定の部分を取得

    • 例:
      text = "名前=田中太郎=30歳"
      parts = text.split('=')  # → ["名前", "田中太郎", "30歳"]
      second_part = parts[1]   # → "田中太郎"
      # または直接
      result = text.split('=')[1]  # → "田中太郎"
      
  • np.mean()関数 - 配列の平均値を計算

    • 例:

      ```python
      import numpy as np
      scores = [85, 92, 78, 96, 88]
      average = np.mean(scores) # → 87.8
      ```
      

履歴が表示されるか複数の計算を行って確認しましょう!

🎉 完成!

おめでとうございます!

今回出来上がった画面はこちらです 👇


実際に様々な計算を実行して動作確認してみましょう!!

🎯 まとめ:電卓アプリで学んだこと

今回作成した電卓アプリは、以下のような多くの重要な概念が含まれています:

  • 変数とデータ型
  • 条件分岐とループ処理
  • エラー処理
  • ライブラリの使用方法
  • 状態管理
  • データの可視化

今回の電卓アプリの特徴:

  • 実用的な機能 - 実際に使える計算機能
  • 履歴管理 - 過去の計算結果を保存・表示
  • 統計情報 - 計算結果の平均値を自動計算
  • エラー対策 - ゼロ割りなどの安全対策

まずは今回紹介したコードの一部を変更して、画面の変化を体験してみてください。例えば、「カンガルー」を「コアラ」に変えたり、「st.success」を「st.info」に変えたりしてみましょう!コードを少し変えるだけで、アプリの表示が変わることを実感できます!!


🎓 プログラミング学習におすすめ

プログラミング未経験の方には CyTech(サイテック) がおすすめです!

CyTech は、未経験から IT エンジニアを目指す人向けのオンライン学習プラットフォームで、基礎から実務レベルのスキルを最短 10 ヶ月で習得できるカリキュラムを提供しています。
HTML/CSS/JavaScript/PHP/SQL/Git などのプログラミング言語に加え、デザイン、英語なども学べる総合的なプラットフォームです。
今後随時学習できるプログラミング言語増加予定!
エンジニア学習にお困りの方はまずは CyTech 無料カウンセリングでお悩み解消!

Discussion