0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Copilot演習:Pythonのコーディング(定められた記述作法を遵守する)

Posted at

Copilot無償版

演習シナリオ

Pythonで顧客管理を行うWebアプリケーションを作成したいと考えています。
ひとことでPythonと言っても、所属する業態や法人により記述作法が定義されています。
この演習では PEP 8(Style Guide for Python Code)
サンプルとして、作法にのっとったコードの生成を試してみます。

演習手順

①作法を認識させます。
この演習では、作法の文書化からとりかかります。
組織内に文書化されているものがあればそちらを流用してください。
次のプロンプトを実行してください。

PEP8にのっとったコーディング作法について生成してください。
このあとPythonのコーディングをしてもらいたいので、
AIに作法を網羅させることができるような粒度でお願いします。

次のような出力を得ることができます。

PEP8(Python Enhancement Proposal 8)は、Pythonコードの可読性と一貫性を高めるためのスタイルガイドです。コーディング作法に移る前に、AIが「作法を網羅できる粒度」でPEP8の要点を整理します。


🧠 PEP8に基づくPythonコーディング作法(網羅的な粒度)

1. インデント

  • スペース4つを使用(タブは使用しない)
def func():
    if True:
        print("Hello")

2. 最大行長

  • 1行は79文字以内(コメントは72文字以内が推奨)

3. 空白の使い方

演算子の前後にスペース

x = a + b

コンマの後にスペース

items = [1, 2, 3]

関数の引数の前後にスペースを入れない

func(a, b)  # OK
func( a, b )  # NG

4. 空行

  • トップレベルの関数やクラスの間には2行の空行
  • クラス内のメソッド間には1行の空行

5. インポートの順序

  1. 標準ライブラリ
  2. サードパーティライブラリ
  3. 自作モジュール
import os
import sys

import numpy as np

from mymodule import myfunc

6. 命名規則

種類 スタイル
変数名 小文字+アンダースコア user_name
関数名 小文字+アンダースコア get_data()
クラス名 キャメルケース UserProfile
定数 全大文字+アンダースコア MAX_SIZE

7. コメント

  • コードの意図を明確にする
  • 英語が推奨(日本語でもOKだが統一する)
  • Docstring(関数やクラスの説明)は三重引用符で記述
def add(a, b):
    """2つの数値を加算して返す"""
    return a + b

8. 不要なコードの削除

  • 未使用の変数、インポート、関数は削除する

9. 例外処理

  • 明示的に例外をキャッチし、適切に処理する
try:
    result = 10 / 0
except ZeroDivisionError:
    print("ゼロ除算エラー")
---
### 10. **可読性のための改行**
- 複雑な式は適切に改行する
```python
total = (first_variable
         + second_variable
         - third_variable)

11. ファイル末尾の改行

  • ファイルの最後には1つの改行を入れる

12. 型ヒント(Python 3.5以降)

def greet(name: str) -> str:
    return f"Hello, {name}"
---
## ✅補足:PEP8チェックツール
- `flake8`
- `black`自動整形
- `pylint`
---

② 作法にのっとってコーディングを実施します。
最初に、先に生成された作法定義またはあなたの組織で準備されている作法定義を認識させます。
次のプロンプトを実施してください。

# 背景
あなたはPythonのコーディングを実施するプロフェッショナルです。
入力に記載された処理のコードを生成してください。
# 命令
先に生成した作法の定義を遵守してコードを生成してください。
/// あなたの組織で定義された文面があればここに貼り付け。 ///
/// その場合この命令の先頭行は削除してください。 ///
定義から外れる場合は、外れた個所を明記し、外れた理由を記載してください。
# 入力
"""
micorosft 365 アカウントでログインできる。
アカウントごとにアクセス権を付与できる。
Azure上のMySQLと接続できる。
Azure上のMySQLのデータを登録、修正、削除できる。
データ登録、修正、削除機能をもった画面を表示できる。
"""
# 出力
すぐにコンパイル可能なPythonコードとして出力してください。
先頭に内容が見て取れる簡潔なプログラム名の案を記載してください。

生成結果を確認してください。

次のような結果が生成されます。

以下は、**「AzureMySQLManager」**という名前のPythonプログラムです。
Microsoft 365アカウントでログインし、Azure上のMySQLに接続してデータの登録・修正・削除ができるWebアプリケーションの構成になっています。


✅ プログラム名: AzureMySQLManager

🔧 機能概要

  • Microsoft 365アカウントでログイン(OAuth想定)
  • アカウントごとのアクセス権管理
  • Azure上のMySQLと接続
  • データ登録・修正・削除機能付きの画面表示

💡 注意点

  • 実行には以下のPythonパッケージが必要です:
    pip install flask mysql-connector-python
    
  • Microsoft 365ログインは簡易的にメールアドレス入力で代用していますが、本番ではAzure AD OAuth2.0認証を使うべきです。

🐍 Pythonコード(Flaskベース)

# プログラム名: AzureMySQLManager
# 機能: Microsoft 365ログイン、アクセス権管理、Azure MySQL接続、データ登録・修正・削除画面

from flask import Flask, render_template_string, request, redirect, session
import mysql.connector

app = Flask(__name__)
app.secret_key = 'your_secret_key'

# Azure MySQL接続設定
DB_CONFIG = {
    'host': 'your-azure-mysql-host.mysql.database.azure.com',
    'user': 'your_user@your-azure-mysql-host',
    'password': 'your_password',
    'database': 'your_database'
}

# 仮のユーザーアクセス権(Microsoft 365ログイン後に取得する想定)
USER_ACCESS = {
    'user1@domain.com': 'admin',
    'user2@domain.com': 'editor'
}

# ログイン画面(Microsoft 365ログインはOAuthで実装する想定)
@app.route('/', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        email = request.form['email']
        if email in USER_ACCESS:
            session['email'] = email
            session['role'] = USER_ACCESS[email]
            return redirect('/manage')
        return 'アクセス権がありません'
    return '''
        <form method="post">
            Microsoft 365 Email: <input name="email">
            <input type="submit" value="Login">
        </form>
    '''

# データ管理画面
@app.route('/manage', methods=['GET', 'POST'])
def manage():
    if 'email' not in session:
        return redirect('/')

    conn = mysql.connector.connect(**DB_CONFIG)
    cursor = conn.cursor()

    if request.method == 'POST':
        action = request.form['action']
        name = request.form['name']
        id = request.form.get('id')

        if action == 'insert':
            cursor.execute("INSERT INTO items (name) VALUES (%s)", (name,))
        elif action == 'update' and id:
            cursor.execute("UPDATE items SET name=%s WHERE id=%s", (name, id))
        elif action == 'delete' and id:
            cursor.execute("DELETE FROM items WHERE id=%s", (id,))

        conn.commit()

    cursor.execute("SELECT id, name FROM items")
    rows = cursor.fetchall()
    conn.close()

    return render_template_string('''
        <h2>ログインユーザー: {{email}} ({{role}})</h2>
        <form method="post">
            ID (更新/削除用): <input name="id"><br>
            名前: <input name="name"><br>
            <button name="action" value="insert">登録</button>
            <button name="action" value="update">修正</button>
            <button name="action" value="delete">削除</button>
        </form>
        <h3>登録済みデータ</h3>
        <ul>
        {% for id, name in rows %}
            <li>{{id}}: {{name}}</li>
        {% endfor %}
        </ul>
    ''', email=session['email'], role=session['role'], rows=rows)

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

📦 補足

  • items テーブルは以下のように作成してください:
CREATE TABLE items (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255)
);

③ AIに自己診断させてみる
生成されたコードに落ち度がないか自己診断させてみます。
次のプロンプトを実行してください。

# 命令
生成されたコードについて、次の視点から診断を実施してください
・セキュリティ脆弱性が含まれていないこと
・コメントの理解が容易であること
・無限ループの可能性が排除できていること
・その他あなたの知見から指摘できること
# 出力
命令内の各項目に対して、表形式で生成してください。
次の5列でお願いします。
診断日時(JST)、診断項目、診断結果、その理由、解消案、その他指摘事項

命令に従って生成されたコードが診断されたことを確認してださい。

自己診断プロンプトは人間が書いたコードの診断にも流用可能です。

④ AIにコードを修正させてみる
診断結果を取り入れてコードの改善を実施してみます。
次のプロンプトを実行してください。

診断結果に基づいて、以前生成したコードを改善してください。
どこが改善されたのか、改善前後の差分がわかるようにコメントも追記してください。

生成結果を確認してください。

次のような結果が生成されます。

了解しました。以下は、改善済みコードです。
HTMLテンプレートはコード内に戻しつつ、診断結果に基づく改善点とコメントは維持しています。


🐍 改善済みコード

# プログラム名: AzureMySQLManager
# 機能: Microsoft 365ログイン、アクセス権管理、Azure MySQL接続、データ登録・修正・削除画面

from flask import Flask, render_template_string, request, redirect, session
import mysql.connector
import os
from datetime import timedelta

app = Flask(__name__)

# 🔐 セキュリティ改善: secret_keyを環境変数から取得
app.secret_key = os.getenv('FLASK_SECRET_KEY', 'default_secret_key')

# 🔐 セッションタイムアウト設定(30分)
app.permanent_session_lifetime = timedelta(minutes=30)

# 🔐 DB接続情報を環境変数から取得
DB_CONFIG = {
    'host': os.getenv('DB_HOST'),
    'user': os.getenv('DB_USER'),
    'password': os.getenv('DB_PASSWORD'),
    'database': os.getenv('DB_NAME')
}

# 仮のユーザーアクセス権(Microsoft 365ログイン後に取得する想定)
USER_ACCESS = {
    'user1@domain.com': 'admin',
    'user2@domain.com': 'editor'
}

def get_db_connection():
    """Azure MySQLへの接続を返す関数"""
    return mysql.connector.connect(**DB_CONFIG)

@app.route('/', methods=['GET', 'POST'])
def login():
    """
    ログイン画面表示と処理
    - Microsoft 365 OAuth2.0認証を実装する前提
    - 現在はメールアドレス入力による簡易認証
    """
    if request.method == 'POST':
        email = request.form['email']
        if email in USER_ACCESS:
            session.permanent = True
            session['email'] = email
            session['role'] = USER_ACCESS[email]
            return redirect('/manage')
        return 'アクセス権がありません'
    return '''
        <form method="post">
            Microsoft 365 Email: <input name="email">
            <input type="submit" value="Login">
        </form>
    '''

@app.route('/manage', methods=['GET', 'POST'])
def manage():
    """
    データ管理画面
    - 登録、修正、削除の操作を提供
    - ユーザー認証とロール表示
    """
    if 'email' not in session:
        return redirect('/')

    conn = get_db_connection()
    cursor = conn.cursor()

    if request.method == 'POST':
        action = request.form['action']
        name = request.form['name']
        id = request.form.get('id')

        # 🛡️ SQLインジェクション対策済み(プレースホルダ使用)
        if action == 'insert':
            cursor.execute("INSERT INTO items (name) VALUES (%s)", (name,))
        elif action == 'update' and id:
            cursor.execute("UPDATE items SET name=%s WHERE id=%s", (name, id))
        elif action == 'delete' and id:
            cursor.execute("DELETE FROM items WHERE id=%s", (id,))

        conn.commit()

    cursor.execute("SELECT id, name FROM items")
    rows = cursor.fetchall()
    conn.close()

    # 🧱 HTMLテンプレートはコード内に保持(分離案は削除済み)
    return render_template_string('''
        <h2>ログインユーザー: {{email}} ({{role}})</h2>
        <form method="post">
            ID (更新/削除用): <input name="id"><br>
            名前: <input name="name"><br>
            <button name="action" value="insert">登録</button>
            <button name="action" value="update">修正</button>
            <button name="action" value="delete">削除</button>
        </form>
        <h3>登録済みデータ</h3>
        <ul>
        {% for id, name in rows %}
            <li>{{id}}: {{name}}</li>
        {% endfor %}
        </ul>
    ''', email=session['email'], role=session['role'], rows=rows)

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

この演習はこれで終了です。
みなさまの業務にご活用ください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?