PR
PR

【Pythonの学習 Day2】現在の時刻を表示するサービスを作ってみる

記事内に広告が含まれています。

Gemini先生と一緒にPythonを勉強する2日目です。

どんなサービスを作るか?

Pythonの学習を始めるにあたり、最初のステップとしてWebサービスを実際に作って動かしてみようと考えました。

ただ、どの程度の複雑さのサービスが学習に適しているのか判断が難しかったため、Gemini先生に相談したところ、以下のサービスを提案してくれました。

  • ToDoアプリ
  • シンプルなブログシステム
  • メモ帳アプリ
  • URL短縮サービス

それぞれ推奨理由も提示されましたが、データベースの知識や操作が必要になるなど、初学者向けの最初のプロジェクトとしては少しハードルが高いと感じました。

そこで、「もう少し簡単なのありますか?」と泣きを入れたところ、次に以下のサービスを提案してくれました。

  • 自己紹介ページ
  • ランダムな名言ジェネレーター
  • 現在の時刻表示ページ

これらはデータベースが不要で、比較的シンプルな構造で実現できそうだと判断し、今回は「現在の時刻表示ページ」から取り組んでみることにしました。

開発環境作成

最初は「pyenv」 + 「uv」 + 「Flask」を使って開発環境を構築します。

これは前回やったので余裕ですね。

プロジェクトディレクトリ作成

プロジェクトで使用するディレクトを「~/project/time_app」という名前で作成します。

$ mkdir ~/project/time_app
$ cd ~/project/time_app

使用するPythonのバージョン指定

プロジェクトで使用するPythonのバージョンを「pyenv」で設定します。

Pythonのバージョン3.13.3は前回インストールしてあるので、今回はそれを使用することにします。

$ pyenv local 3.13.3

設定内容を確認しておきます。

$ pyenv versions
  system
* 3.13.3 (set by /home/tamohiko/project/time_app/.python-version)
$ python --version
Python 3.13.3

仮想環境作成

「uv venv」を使って仮想環境を作成します。

$ uv venv
Using CPython 3.13.3 interpreter at: /home/tamohiko/.pyenv/versions/3.13.3/bin/python3.13
Creating virtual environment at: .venv
Activate with: source .venv/bin/activate

作成した仮想環境を有効化します。

$ source .venv/bin/activate
(time_app) tamohiko@vaio:~/project/time_app $ 

Flaskインストール

開発に使用するWeb開発フレームワークである「Flask」をインストールします。

$ uv pip install Flask
Resolved 7 packages in 238ms
Installed 7 packages in 25ms
 + blinker==1.9.0
 + click==8.2.0
 + flask==3.1.0
 + itsdangerous==2.2.0
 + jinja2==3.1.6
 + markupsafe==3.0.2
 + werkzeug==3.1.3

これで、開発環境の構築は完了です。

時刻表示サービスの作成

それでは、いよいよ時刻表示サービスの開発に取り掛かります。

まず、Gemini先生に基本的な時刻表示サービスの作り方を尋ねたところ、プロジェクト用のディレクトリ「~/project/time_app」内に、以下の構成でファイルを用意するようアドバイスを受けました。

~/project/time_app
├── templates
│   └── time.html  # ブラウザに表示する時刻のHTMLテンプレート
└── time_app.py     # Flaskアプリケーションのメインプログラム

time_app.py作成

サービスのメインプログラムを「time_app.py」という名前で作成します。

$ vi time_app.py

Gemini先生が教えてくれたプログラムは以下のとおりです。

# 必要なモジュールをインポート
from flask import Flask, render_template
import datetime # 現在時刻を取得するために必要

# Flaskアプリケーションのインスタンスを作成
app = Flask(__name__)

# '/' (ルートURL) にアクセスがあった場合の処理を定義
@app.route('/')
def show_time():
    # 現在の日時を取得
    now = datetime.datetime.now()

    # 日時を表示する形式にフォーマット
    time_string = now.strftime("%Y年%m月%d日 %H時%M分%S秒")

    # 'time.html' というテンプレートに、取得した時刻文字列を渡して表示
    # 'current_time' という名前でテンプレート側で使えるようにする
    return render_template('time.html', current_time=time_string)

# このファイルが直接実行された場合に開発用サーバーを起動
if __name__ == '__main__':
    app.run(debug=True) # debug=True は開発中に便利

コードの解説

Gemini先生にコードを一行ずつ解説してもらったので、まずはその内容を自分なりにまとめてみました。

さらに、学習を進める中で出てきた追加の疑問点も質問し、その回答も得られたので、ここで共有します。

from flask import Flask, render_template

「from flask」flaskモジュールから「import Flask, render_template」Flaskとrender_templateをインポートする。(プログラム内で直接使用できるようにする)

この行では、Webアプリケーションフレームワークであるflaskというモジュール(from flask)から、以下の2つの重要な要素をインポートしています。(import Flask, render_template)

これにより、これらの要素を私たちのプログラム内で直接利用できるようになります。

Flask

Webアプリケーションの本体を作成するためのクラスで、よく「設計図」に例えられます。

app = Flask(__name__) のように記述することで、このFlaskクラス(設計図)を基にして、app という名前のWebアプリケーションの実体(オブジェクトまたはインスタンス)を作成します。

render_template

HTMLファイルを読み込み、その中にPythonプログラム側で用意した動的なデータ(例えば、今回の時刻表示サービスであれば現在の時刻)を埋め込み、最終的なWebページとしてユーザーのブラウザに表示するための内容を生成するFlaskの関数です。

import flaskとした場合

「import flask」とだけ記述した場合は、flaskモジュール全体が読み込まれます。

この場合、そのモジュール内に定義されている Flaskクラスやrender_template関数などを使う際には、「app = flask.Flask(__name__)」や「flask.render_template」のように、「モジュール名.」を接頭辞として毎回記述する必要があります。

記述が長くなりますが、どのモジュールの機能を使用しているのかが明確になるという利点もあります。

importできる物って何?

import文を使って、他のファイルやライブラリから様々な要素を自分のプログラムに取り込むことができると学びましたが、具体的にどのような種類のものをインポートできるのでしょうか?

Gemini先生に尋ねてみたところ、主に以下のものがあると教えてくれました。

  • モジュール(Module):Pythonのコードが書かれたファイル(拡張子が .py のファイル)のことで「関数」「クラス」「変数」などをまとめたもの
  • クラス (Class):モジュールの中に定義されている「設計図」のことで、オブジェクト(実体)を作るために使われる
  • 関数 (Function):モジュールやクラスの中に定義されている、特定の処理をまとめたもの
  • 変数(Variable):モジュールレベルで定義されている値を保存している
  • 慣習的な定数 (Constant):Pythonには厳密な意味での「定数(一度設定したら変更できない値)」の仕組みはありませんが、慣習として「変更しないことが意図される変数」を大文字で記述し、定数のように扱います。これらもモジュールレベルの変数の一種としてインポートできます。
それぞれの見分け方

import文で取り込んだものがモジュールなのか、クラスなのか、それとも関数なのかを判断する方法についても質問してみました。

そうすると、100%確実というわけではありませんが、Pythonの公式スタイルガイドである「PEP 8」で推奨されている命名規則(名前の付け方のルール)に従って書かれている場合、名前の見た目からある程度推測することができることと、以下のルールを教えてくれました。

  • モジュール名
    • すべて小文字で書かれることが多い
    • 単語が複数ある場合は、アンダースコア「_」でつなぐことがある
    • 例:os、math, sys
  • クラス名
    • 各単語の頭文字を大文字にする「CapWords」または「PascalCase」というスタイルで書かれることが多い
    • 例:Flask、HttpRequest
  • 関数名
    • すべて小文字で書かれ、単語が複数ある場合はアンダースコア「_」でつなぐことが多い(スネークケースと呼ばれている)
    • 例:render_template, calculate_sum, get_user_data
  • 変数名
    • 関数名と同じくすべて小文字で書かれ、単語が複数ある場合はアンダースコア「_」でつなぐことが多い
    • 例:user_name, item_list, total_count
  • 定数名
    • すべて大文字で書かれ、単語が複数ある場合はアンダースコア「_」でつなぐことが多い
    • 例:MAX_LENGTH, PI, DEFAULT_TIMEOUT
注意点

これらの命名規則はあくまで「推奨」であり、全てのコードがこの規則に従っているわけではありません。

しかし、標準ライブラリや多くの有名なサードパーティライブラリはこの規則に沿って書かれているため、知っておくとコードを読む際の大きな助けになります。

import datetime

Pythonで日付や時刻を扱うための機能がまとめられた標準ライブラリの一部である、datetimeという名前のモジュールをインポートしています。

app = Flask(__name__)

app = Flask(...)の部分は、Flaskクラスのインスタンスを作成し、appという名前の変数に割り当てている。

このappがこれから作成するアプリケーションそのものとなる。

ルーティングの定義、リクエストの処理、レスポンスの生成などの動作は、このappを介して行わる。(正直まだ良くわからんです…)

()のなかにある「__name__」について

「__name__」はPythonが自動的に用意してる特殊変数の一つで、現在動作しているプログラムファイルのに関する情報が格納されています。

この「__name__」の値は、そのファイルがどのように実行されたかによって変わります。

ファイルを直接実行した場合

例えば、time_app.pyファイルをコマンドラインから「python time_app.py」といったように直接実行すると、「__name__」の値はは「"__main__"」という特別な文字列になります。

これは、「このファイルがプログラムのメインの実行ポイントである」という意味合いです。(自分がメインで動作しているという意味)

モジュールとしてインポートされた場合

別のPythonファイルから「import time_app」のようにモジュールとしてインポートされて使われる場合、「time_app.py」内での「__name__」の値は、そのモジュール名である「time_app」(拡張子.pyを除いたもの)になります。(例: my_module.pyというモジュールの場合、拡張子.pyを除いたmy_moduleとなる)

Flaskクラスに「__name__」を渡す理由

Flaskは、この「__name__」の情報を基にして、作成されるWebアプリケーションのルートパス (root path) を決定します。

ルートパスとは、アプリケーションがファイルシステム上のどこに位置しているかの基準となる場所(ディレクトリ)のことです。

このルートパスが正しく設定されることで、Flaskアプリケーションは以下のようなリソースの場所を適切に見つけ出すことができます。

  • テンプレートファイル: ルートパスからの相対パスで「templates」フォルダ内にあるHTMLファイルなど。
  • 静的ファイル: CSS、JavaScript、画像ファイルなどが格納される「static」フォルダ。
  • 設定ファイル: app.config.from_pyfile('config.py') のように、相対パスで設定ファイルを読み込む場合の基準。

正直なところ、このルートパスの概念や、「__name__」が具体的にどのように影響するのかについては、私もまだ完全に腑に落ちているわけではありません。

Flaskがアプリケーションの置き場所を正しく把握するために、この「__name__」をヒントにしているんだなという程度の理解です。

おそらく、実際にテンプレートファイルや静的ファイルを扱ったり、アプリケーションの構成が複雑になったりする中で、このルートパスの重要性や __name__ の役割がより具体的に感じられるようになるのだと思いますが、今はまず「そういう仕組みがある」ということを頭の片隅に置きつつ、先に進んでいこうと思います。

@app.route('/')

「/」というURL(例: http://127.0.0.1:5000/)にアクセスがあったときに、直後の「show_time()」関数を実行するように設定しています。

def show_time():

Flaskアプリケーションにおいて、特定のURL(この場合はルートURL /)にアクセスがあったときに呼び出される「ビュー関数」として「show_time()」という名前で以下の処理を定義しています。

  • now = datetime.datetime.now()
  • time_string = now.strftime("%Y年%m月%d日 %H時%M分%S秒")
  • return render_template('time.html', current_time=time_string)

now = datetime.datetime.now()

Pythonの標準ライブラリである「datetime」モジュールの中にある「datetime」クラスを使用して、「now()」クラスメソッドを呼び出し、現在の日時を取得し結果を変数「now」に格納しています。

モジュール名とクラス名が同じ「datetime」なので分かりづらくなっていますが、「モジュール名.クラス名.クラスメソッド」という形になっています。

「now()」メソッドはコンピュータのシステム設定に基づいたローカルな日時を返します。

datetime.datetime.now(tz=タイムゾーン)で指定したタイムゾーンの時刻を取得することができます。

クラスメソッドとは

クラスメソッドとは、クラス自身に関連付けられたメソッドで、インスタンスを作成しなくても呼び出すことができます。

time_string = now.strftime("%Y年%m月%d日 %H時%M分%S秒")

「now」には「datetime.datetime.now()」によって取得された値が格納されていて、「strftime(形式)」メソッドを使用して、取得した日時を人間が読みやすい文字列の形式に変換し、「time_string」という変数に格納しています。

return render_template('time.html', current_time=time_string)

Pythonで処理した結果(今回はフォーマットされた現在時刻)をユーザーのブラウザに表示するためのHTMLページを生成し、それをレスポンスとして返しています。

この役割を担っているのが、Flaskフレームワークが提供している「render_template」関数です。

render_template() 関数の役割

この関数は、あらかじめ用意しておいたHTMLテンプレートファイル(今回の場合time.html)に、動的なデータを埋め込み、最終的なHTMLコンテンツをレンダリング(描画・作成)します。

Flaskはデフォルトで Jinja2 (ジンジャツー) という強力なテンプレートエンジンを使用しており「render_template」関数はこのJinja2エンジンを介して動作します。

引数の意味

「time.html」は、レンダリングに使用するHTMLのテンプレートを指定しています。

「current_time=time_string」は、HTMLテンプレートに渡したいデータを指定しています。

今回の場合、templatesフォルダにある「time.html」を使って「time_string」の値を「current_time」という名前で埋め込み、「完成したHTMLページをユーザーに表示して」という指示を出しています。

if __name__ == '__main__': app.run(debug=True)

このPythonファイルが直接実行されたとき(python app.py のように)、「app.run()」でFlaskの開発用サーバーを起動するというお決まりの書き方です。

「debug=True」にしておくと、コードを変更したときに自動でサーバーが再起動したり、エラー発生時に詳しい情報がブラウザに表示されたりして、開発がとても楽になります。

app.run() で起動するサーバーは、その手軽さから開発時には非常に便利ですが、あくまで開発用途に特化したものです。

セキュリティやパフォーマンスの観点から、実際にサービスを公開する本番環境でこの開発用サーバーを使用することは推奨されません。

本番環境ではより堅牢で高性能な WSGI (Web Server Gateway Interface) サーバーを利用します。

代表的なWSGIサーバーとしては、「Gunicorn」や「uWSGI」などがあり、これらは多数の同時アクセス処理や安定した運用に適しています。

「templates/time.html」作成

実際にユーザーのブラウザに表示されるWebページの元となる、HTMLテンプレートファイルを作成します。

Flaskでは、慣習的にプロジェクトルート直下に templates という名前のフォルダを作成し、その中にHTMLファイルを配置します。

今回は、「templates/time.html」 というファイル名で、現在時刻を表示するためのHTMLテンプレートを用意します。

この templates/time.html ファイルの主な役割は以下の通りです。

  • Webページの基本的な骨組み(HTML構造)を定義します。
  • 最終的に、データが埋め込まれた完成形のHTMLとして、ユーザーのWebブラウザに送信され、表示される内容を決定します。

Flaskでは、慣習的にプロジェクトのルートディレクトリ(time_app.py と同じ階層)に「templates」という名前のフォルダを作成し、その中にHTMLファイルを配置します。

まずは、この「templates」フォルダを作成し、その中に「time.html」ファイルを作成していきます。

$ mkdir templates
$ cd templates
$ vi time.html

作成するファイルの内容は以下のとおりです。


<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>現在の時刻
        body { font-family: sans-serif; text-align: center; margin-top: 50px; }
        h1 { color: #333; }
        p { font-size: 2em; color: #555; }
    </style>
</head>
<body>
    <h1>現在のサーバー時刻です!</h1>
    <p>{{ current_time }}</p>
</body>
</html>

この「time.html」ファイルですが、ただのHTMLファイルというわけではありません。

Flaskは、HTMLテンプレートを処理するために、デフォルトで「Jinja2」 (ジンジャツー) というテンプレートエンジンを利用します。

「time.html」も、この「Jinja2」のルールに従って記述することで、Pythonから渡された動的な情報をHTMLに埋め込むことができるようになります。

「Jinja2」の機能は多岐にわたりますが、最も基本的でよく使われるのが、Python側(ビュー関数)から渡された変数の値をHTML内に表示する機能で、以下のような特別な記法(二重中括弧)を使って行います。

{{ 変数名 }}

今回の場合は、「time_app.py」の「return render_template('time.html', current_time=time_string)」部分で、「current_time」という名前の変数に時刻の文字列を格納しています。

これを「{{ current_time }}」形で「time.html」に記述しています。

Jinja2の使い方例

{{変数}}といった変数の埋め込み以外の使い方の例です。

  • {% if ... %} ... {% else %} ... {% endif %} のような条件分岐
  • {% for item in my_list %} ... {% endfor %} のようなループ処理
  • 他のテンプレートファイルを読み込んだり (インクルード)、テンプレートを継承したり (テンプレート継承)

Jinja2については後で学習することにします。

time_app.py実行

「time_app.py」と「templates/time.html」の2つのファイルが揃いましたので、実際に動作を確認してみましょう!

$ cd ../
$ python ./time_app.py 
 * Serving Flask app 'time_app'
 * Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 931-071-873

これで、Flaskの開発サーバが起動しました。

メッセージの中に「Running on http://127.0.0.1:5000」と表示されているのが、アプリケーションにアクセスするためのURLです。

また、「Debug mode: on」となっていることから、デバッグモードで起動していることも確認できますね。

WARNINGメッセージは、「これは開発用サーバーなので、本番環境では使わないでね」という、以前にも触れた注意喚起です。

動作確認

いよいよ、Webサービスの動作確認を行ってみます。

Webブラウザで「http://127.0.0.1:5000」にアクセスします。

無事、ブラウザに現在の時刻が表示されました!…が、アクセスした瞬間の時刻が表示されるだけで、時計のようにリアルタイムで時刻が更新されていくわけではないようです。

時計のように現在の時刻が表示され続けるのを時計のようなサービスをイメージしていたので、なんか「これじゃない…」という感じがします。

ちなみに、ブラウザでアクセスした後のターミナルには、アクセスしたログが表示されていました。

 * Debugger is active!
 * Debugger PIN: 931-071-873
127.0.0.1 - - [14/May/2025 14:43:46] "GET / HTTP/1.1" 200 -

これは、http://127.0.0.1:5000 の / というパスに対して GET リクエストがあり、サーバーが正常に応答した(ステータスコード 200)ことを示しています。

このように、開発サーバーはアクセスログも表示してくれるので、デバッグの際に役立ちます

今後の改善点

とりあえず、Flaskを使ってWebブラウザに動的な情報(今回はアクセスした時点の時刻)を表示させる、という最初の目標は達成できました!

しかし、先ほどの「これじゃない感」を解消し、より自分が欲しいと思えるWeb時計に近づけるために、以下のような機能を実装していきたいと考えています。

  • リアルタイムの時間を表示する
  • 背景をつける
  • 時間毎に背景を変更
  • 文字や背景を自分で変更できるようにする
  • CSSで装飾する

これらの改善点を一つずつクリアしていくことで、PythonとFlask、そしてWeb技術全般の理解を深めていけるのではないかと期待しています。

今日のまとめ

今日の学習内容をまとめました。

PythonとFlaskを使った開発環境構築

Python + pyenv + uv + Flaskを使った開発環境の構築は、前回学んだので今回も問題なくできました。

同じ内容の環境であれば、今後も問題なく構築できそうです。

Flaskによる基本的なWebサービスの仕組みについて

構成

主な処理を書くPythonファイル(例:time_app.py)と、表示を担当するHTMLテンプレートファイル(例:templates/time.html)での基本的なWebサービスの作り方。

ルーティング

@app.route('/') のように記述することで、特定のURLへのアクセスに対して実行するPython関数(ビュー関数)を紐付けることができる。

現時点では、いまいち理解が足りていないような気がするので、後ほど確認を行っていきたいと思います。

ビュー関数

「show_time()」という名前で以下の処理を行うビュー関数を作成した。

  • now = datetime.datetime.now():現在の日時を取得
  • time_string = now.strftime("%Y年%m月%d日 %H時%M分%S秒"): 取得した日時を人間が読みやす形にフォーマット
  • return render_template('time.html', current_time=time_string): HTMLテンプレート(time.html)を使ってウェブページをレンダリングし結果(ブラウザに表示される内容)を返す

Pythonでモジュールなどをimportする方法

インポート対象と命名規則(「PEP 8」で推奨されている)は以下の通り。

  • モジュール: すべて小文字で書かれることが多い
  • クラス: 各単語の頭文字を大文字にする「CapWords」または「PascalCase」というスタイルで書かれることが多い
  • 関数:すべて小文字で書かれ、単語が複数ある場合はアンダースコア「_」でつなぐことが多い(スネークケースと呼ばれている)
  • 変数:小文字で書かれ、単語が複数ある場合はアンダースコア「_」でつなぐことが多い
  • 慣習的な定数:すべて大文字で書かれ、単語が複数ある場合はアンダースコア「_」でつなぐことが多い

Flask(__name__)の意味

「__name__」は特殊変数で、Flaskのルートパスを決定するのに使われる。

ルートパスが設定されることで、Flaskは「テンプレートファイル」「静的ファイル(CSS、JavaScript、画像ファイル等)」「設定ファイル」等を見つけ出すことができるようになる。

Flask開発サーバの起動方法

Flaskの開発サーバーを起動する方法と、デバッグモード(ログの表示等)の利便性を確認。

本番環境では別途WSGIサーバー「Gunicorn」や「uWSGI」などが必要となる。

コメント

タイトルとURLをコピーしました