<?xml version="1.0" encoding="utf-8" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>masa-montyのブログ</title>
<link>https://ameblo.jp/masa-monty/</link>
<atom:link href="https://rssblog.ameba.jp/masa-monty/rss20.xml" rel="self" type="application/rss+xml" />
<atom:link rel="hub" href="http://pubsubhubbub.appspot.com" />
<description>ブログの説明を入力します。</description>
<language>ja</language>
<item>
<title>データベース作成</title>
<description>
<![CDATA[ <p>Pythonの<a href="https://docs.python.org/ja/3/library/sqlite3.html" rel="noopener noreferrer" target="_blank">sqlite3</a>ライブラリを利用するので、インポートします</p><pre style="font-size:small;">import sqlite3</pre><p>&nbsp;</p><p>初期化処理ではデータベースの作成と、JSONファイルから読み込んだデータを</p><p>データベースに追加しています</p><p>&nbsp;</p><p>データベースはファイルで保存されます</p><p>※MYSQLなどはファイルとして見えないようになっています</p><p>　（どのような製品でもデータを保持するためにはファイルは必要ですけど…）</p><p>バイナリファイルなので中身の確認は難しいですが、ファイルが存在することで、</p><p>データベースが存在することがわかります</p><p>データベースファイル名をemployee.dbにして、ファイルが存在しないであれば、</p><p>データベースを作成するようにしてます</p><p>&nbsp; &nbsp; self.mydb: str = 'employee.db'&nbsp;</p><p>&nbsp; &nbsp; if (not os.path.exists(self.mydb)):</p><p>&nbsp;</p><p>データベースファイルに接続します</p><p>データベースファイルがなければ作成してくれます</p><p>なので「CREATE DATABASE IF NOT EXISTS&nbsp;employee.db」は不要です</p><p>データベースオブジェクトを返してくれます</p><p>以降、データベースオブジェクトを利用してデータベース操作を行います</p><p>&nbsp; &nbsp; &nbsp; &nbsp; conn = sqlite3.connect(self.mydb)</p><p>&nbsp;</p><p>データベース接続オブジェクトを利用してカーソルを作成します</p><p>カーソルはSQL 文を実行し、SQL クエリから結果を取得するためのオブジェクトです</p><p>&nbsp; &nbsp; &nbsp; &nbsp; cursor = conn.cursor()</p><p>&nbsp;</p><p>データベースにテーブルを作成します</p><p>社員情報テーブル、社員趣味情報テーブル、社員特技情報テーブルの３つを作成して</p><p>います</p><p>※Pythonは、シングルクォーテーションまたはダブルクォーテーション３つで</p><p>　文字列を挟むと改行した文字列を１つの文字列とみなしてくれます</p><p>　私は好きではないので、後ほど修正しておきます</p><p>　※ちなみに、改行に続くスペースも文字列の中に含まれてしまいますが</p><p>　　sqlite3が大丈夫なように作成してくれています</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;cursor.execute("""CREATE TABLE IF NOT EXISTS tbl_employee(</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; no INTEGER PRIMARY KEY,</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name TEXT,</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; birth TEXT,</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sex TEXT)""")</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # 社員趣味情報テーブルを作成する</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cursor.execute("""CREATE TABLE IF NOT EXISTS tbl_employee_hobby(</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; id INTEGER PRIMARY KEY AUTOINCREMENT,</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; no INTEGER,</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; hobby TEXT)""")</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # 社員特技情報をテーブルを作成する</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cursor.execute("""CREATE TABLE IF NOT EXISTS tbl_employee_skill(</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; id INTEGER PRIMARY KEY AUTOINCREMENT,</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; no INTEGER,</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; skill TEXT)""")</p><p>&nbsp;</p><p>社員情報テーブルに追加する処理は以下です</p><p>SQLコマンドを作成するときに文字列のformatメソッドを利用しています</p><p>文字列内に{0],{1},…と記述しておいて、それに対応する文字列をformatメソッドの</p><p>引数に順番に並べて記述すると、{0},{1]に割り当てて文字列を作成してくれます</p><p>なお、1行で式が記述できないときは「\」を行の最後に記述すると次の行も１つの</p><p>行とみなしてくれます</p><p>その後、SQL文を実行することにより、テーブルに情報を追加します</p><p>このひとまとまりの情報を「行」と呼びます</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sql_emp: str = \<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "INSERT INTO tbl_employee VALUES " + \<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "('{0}', '{1}', '{2}', '{3}')".format(<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; str(emp['no']),<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; emp['name'],<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; emp['birth'],<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; emp['sex'])<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cursor.execute(sql_emp)<br>&nbsp;</p><p>社員趣味情報テーブル、社員特技情報テーブルも同様ですが、主キーは自動生成して</p><p>もらうので、行に追加する情報としては記述していません</p><p>&nbsp;</p><p>最後にカーソルを閉じて、データベース接続を閉じて終了です…</p><p>&nbsp; &nbsp; &nbsp; &nbsp; cursor.close()<br>&nbsp; &nbsp; &nbsp; &nbsp; conn.commit()<br>&nbsp; &nbsp; &nbsp; &nbsp; conn.close()<br>&nbsp;</p><p>何か１つ余分な記述がありますね…</p><p>commitは「送り込む、収容する」という意味の英単語です</p><p>&nbsp;</p><p>「INSERT」で情報を追加したのですが、実はデータベースには格納されていません</p><p>複数テーブルに複数行を追加していますが、途中で不具合が発生したときは追加が</p><p>中途半端になってしまいますよね</p><p>一連の処理の一部でもかけてしまったら、例えば趣味の追加が失敗したら、趣味が</p><p>なくなってしまいます</p><p>&nbsp;</p><p>複数行に複数行を追加するような一連の操作を「トランザクション」と呼びます</p><p>&nbsp;</p><p>データベースは「常に正しい状態を維持する」機能を持っているのです</p><p>特に「更新を伴う処理」に対しては</p><p>「トランザクション」が無事に成功するまではデータベースに「正しい情報『群』」を</p><p>追加しないようにしてくれているのです</p><p>そして、プログラムが最後まで正しく動作した時にcommitメソッドを発行して、</p><p>データベースに変更した（今回は追加した）内容を送り込んでいるのです</p><p>なかなかの優れものですね</p><p>※ちなみに失敗した時に、明示的にデータベースへの操作（変更とか追加とか）を</p><p>　無効にするのはrollbackメソッドです</p><p>　初期化処理内では、データベース接続オブジェクトでテーブルへのデータ追加</p><p>　トランザデータ処理しか行ってないので、rollbackメソッドを意識してません</p><p>　失敗したら、どっかで例外が発生してccommitメソッド発行されずに終了する</p><p>　ので問題ないです</p><p>　割といい加減なようですけど、これで大丈夫だと思います</p><p>　（複数のトランザクションがなければ大丈夫です）</p><p>&nbsp;</p>
]]>
</description>
<link>https://ameblo.jp/masa-monty/entry-12964449740.html</link>
<pubDate>Tue, 28 Apr 2026 17:59:13 +0900</pubDate>
</item>
<item>
<title>データベース実装</title>
<description>
<![CDATA[ <p>演習問題１のプログラムをベースにデータベースを利用するプログラムを作成して</p><p>みましょう</p><p><br>社員リストはJSONファイルから読み込みます</p><p>&nbsp;</p><p>【emplist.json】</p><pre style="font-size: small;">{    "data": [        {            "no": 2601,            "name": "鈴木一郎",            "birth": "1974/02/09",            "sex": "男",            "skill": ["野球"]        },        {            "no": 2602,            "name": "山田花子",            "birth": "1992/03/31",            "sex": "女",            "hobby": ["料理"],            "skill": ["ピアノ"]        },        {            "no": 2603,             "name": "佐藤翠",            "birth": "2008/11/23",            "sex": "女",            "hobby": ["キャンプ"]        },        {            "no": 2604,             "name": "高橋湊",            "birth": "2000/07/10",            "sex": "男"        },        {            "no": 2605,             "name": "伊藤陽菜",            "birth": "2000/12/24",            "sex": "女",            "hobby": ["水泳", "ゴルフ"],            "skill": ["料理"]        },        {            "no": 2606,             "name": "渡辺謙",            "birth": "1970/05/31",            "sex": "男",            "hobby": ["料理"],            "skill": ["キャンプ", "釣り"]        }    ]}</pre><p>演習問題１の辞書に保存する部分をデータベースに保存するようにしました</p><p>（解説は次回に続く）</p><p>&nbsp;</p><p>【employee.py】</p><pre style="font-size: small;">######################################################################## 社員情報#                                                Copyrint 2026 Precede.#######################################################################import datetimeimport enumimport jsonimport osimport sqlite3class ErrMsg(enum.StrEnum):    ''' エラーメッセージ        Args:            enum.StrEnum : 文字列列挙クラス        Returns:            None    '''    # 「社員リストが見つかりません」    LIST_NOT_FOUND = "No employee list."    # 「社員リストへの登録がありません」    LIST_EMPTY = "No one is registered on the employee list."    # 「社員番号がありません」    EMPLOYEE_NO_INVALID = "The employee number is invalid."    # 「社員番号が不正です」    EMPLOYEE_NO_NOT_FOUND = "Employee number not found."    # 「管理者に問い合わせてください」    UNKNOW = "Please contact your system administrator."class Employee:    ''' 社員情報        Args:            None        Returns:            社員情報(str)    '''    def __init__(self):        ''' コンストラクタ            Args:                self : 自分自身            Returns:                None        '''        # エラーコード        self.err_msg: ErrMsg = None        # 社員リストファイル名        self.inp_filename: str = "emplist.json"        # ログファイル        self.log_filename: str = "employee.log"        # データベース名プロパティを設定する        self.mydb: str = 'employee.db'        # データベースが存在しない場合        if (not os.path.exists(self.mydb)):            # データベースを作成する            conn = sqlite3.connect(self.mydb)            # カーソルを作成する            cursor = conn.cursor()            # 社員情報テーブルを作成する            cursor.execute("""CREATE TABLE IF NOT EXISTS tbl_employee(                              no INTEGER PRIMARY KEY,                              name TEXT,                              birth TEXT,                              sex TEXT)""")            # 社員趣味情報テーブルを作成する            cursor.execute("""CREATE TABLE IF NOT EXISTS tbl_employee_hobby(                              id INTEGER PRIMARY KEY AUTOINCREMENT,                              no INTEGER,                              hobby TEXT)""")            # 社員スキル情報をテーブルを作成する            cursor.execute("""CREATE TABLE IF NOT EXISTS tbl_employee_skill(                              id INTEGER PRIMARY KEY AUTOINCREMENT,                              no INTEGER,                              skill TEXT)""")            # 社員リストファイルが存在する場合            if (os.path.exists(self.inp_filename)):                # 社員リストファイルが空の場合                if (os.path.getsize(self.inp_filename) == 0):                    # エラーメッセージに「社員リストへの登録がありません」を設定する                    self.err_msg = ErrMsg.LIST_EMPTY                # 社員リストファイルが空でない場合                else:                    # 社員リストファイルを開く                    with open(self.inp_filename, "r", encoding="utf-8") as fn:                        # 社員情報数分繰り返す                        for emp in json.load(fn)['data']:                            # 社員情報追加コマンドを編集する                            sql_emp: str = \                                "INSERT INTO tbl_employee VALUES " + \                                "('{0}', '{1}', '{2}', '{3}')".format(                                    str(emp['no']),                                    emp['name'],                                    emp['birth'],                                    emp['sex'])                            # 社員情報を社員情報テーブルに追加する                            cursor.execute(sql_emp)                            # 社員情報に趣味が登録されている場合                            if ('hobby' in emp):                                # 社員情報の趣味数分繰り返す                                for hby in emp['hobby']:                                    # 社員趣味情報追加コマンドを編集する                                    sql_emp_hby: str = \                                        "INSERT INTO tbl_employee_hobby " + \                                        "(no, hobby) VALUES " +\                                        "('{0}', '{1}')".format(str(emp['no']),                                                                hby)                                    # 社員趣味情報を社員趣味情報テーブルに追加する                                    cursor.execute(sql_emp_hby)                            # 社員情報に特技が登録されている場合                            if ('skill' in emp):                                # 社員情報の特技数分繰り返す                                for skl in emp['skill']:                                    # 社員特技情報追加コマンドを編集する                                    sql_emp_skl: str = \                                        "INSERT INTO tbl_employee_skill " + \                                        "(no, skill) VALUES " + \                                        "('{0}', '{1}')".format(str(emp['no']),                                                                skl)                                    # 社員特技情報を社員特技情報テーブルに追加する                                    cursor.execute(sql_emp_skl)            # 社員リストファイルが存在しない場合            else:                # エラーメッセージに「社員リストが見つかりません」を設定する                self.err_msg = ErrMsg.LIST_NOT_FOUND            # カーソルを閉じる            cursor.close()            # 変更を確定する            conn.commit()            # データベースを閉じる            conn.close()        return    def get(self, emp_no: str = None):        ''' 社員情報を標準出力する            Args:                self   : 自分自身                emp_no : 社員番号            Returns:                None        '''        # 戻り値初期化        ret: str = ""        # エラーメッセージが設定されてない場合        if (self.err_msg is None):            # 社員番号が数値文字列、かつ、４桁の場合            if (emp_no.isdigit() and (len(emp_no) == 4)):                # データベースを開く                conn = sqlite3.connect(self.mydb)                # カーソルを作成する                cursor = conn.cursor()                # 社員情報取得コマンド編集                sql_emp = "SELECT * FROM tbl_employee " + \                          "WHERE no = '{0}'".format(emp_no)                # 社員情報取得コマンド実行                cursor.execute(sql_emp)                # 社員情報行を取得する                row = cursor.fetchone()                # 社員情報がある場合                if (row is not None):                    # 現在の日付を取得                    now_date = datetime.datetime.now()                    # 誕生日を日付時刻型に変換する                    birth_date = datetime.datetime.strptime(row[2], '%Y/%m/%d')                    # 年齢＝現在年－誕生年                    age = now_date.year - birth_date.year                    # 誕生月を超えた場合                    if (now_date.month &gt; birth_date.month):                        # 年齢に１歳加える                        age += 1                    # 誕生月の場合                    elif (now_date.month == birth_date.month):                        # 誕生日を超えた場合                        if (now_date.day &gt;= birth_date.day):                            # 年齢に１を加える                            age += 1                    # 戻り値に社員番号、社員名、年齢、性別を設定する                    ret = str(row[0]) + " " + row[1] + \                        "(" + str(age) + ") " + row[3]                    # 趣味特技なし                    flg_hobby_skill: bool = False                    # 社員趣味情報取得コマンド編集                    sql_emp_hby = "SELECT hobby FROM tbl_employee_hobby " + \                                  "WHERE no = '{0}'".format(emp_no)                    # 社員趣味情報取得コマンド実行                    cursor.execute(sql_emp_hby)                    # 社員趣味情報行を取得する                    rows_emp_hby = cursor.fetchall()                    # 社員趣味情報がある場合                    if (len(rows_emp_hby) &gt; 0):                        # 戻り値に" &lt;趣味:"を追加                        ret += " &lt;趣味:"                        # 社員趣味情報数分繰り返す                        for i in range(len(rows_emp_hby)):                            # 最初でない場合                            if (i &gt; 0):                                # カンマを追加                                ret += ","                            # 戻り値に趣味を追加                            ret += rows_emp_hby[i][0]                        # 趣味特技あり                        flg_hobby_skill = True                    # 社員特技情報取得コマンド編集                    sql_emp_skl = "SELECT skill FROM tbl_employee_skill " + \                                  "WHERE no = '{0}'".format(emp_no)                    # 社員特技情報コマンド実行                    cursor.execute(sql_emp_skl)                    # 社員特技情報行を取得する                    rows_emp_skl = cursor.fetchall()                    # 社員特技情報がある場合                    if (len(rows_emp_skl) &gt; 0):                        # 趣味が登録されてない場合                        if (not flg_hobby_skill):                            # 戻り値に" &lt;"を追加                            ret += " &lt;"                        # 趣味が登録されている場合                        else:                            # メッセージに"/"を追加                            ret += "/"                        # メッセージに"特技:"                        ret += "特技:"                        # 社員特技情報数分繰り返す                        for i in range(len(rows_emp_skl)):                            # 最初でない場合                            if (i &gt; 0):                                # カンマを追加                                ret += ","                            # 戻り値に特技を追加                            ret += rows_emp_skl[i][0]                        # 趣味特技あり                        flg_hobby_skill = True                    # 趣味特技ありの場合                    if (flg_hobby_skill):                        # 戻り値に"&gt;"を追加                        ret += "&gt;"                    # ログ出力する                    self.output_log(ret, emp_no)                # 社員情報がない場合                else:                    # 戻り値に「社員番号がありません」を設定する                    ret = ErrMsg.EMPLOYEE_NO_NOT_FOUND                # カーソルを閉じる                cursor.close()                # データベースを閉じる                conn.close()            # 社員番号が数値文字列以外、または、４桁でない場合            else:                # 戻り値に「社員番号が不正です」を設定する                ret = ErrMsg.EMPLOYEE_NO_INVALID                # エラーメッセージをログ出力する                self.output_log("%s(%s)" % (ret, self.err_msg))        # エラーメッセージが設定されている場合        else:            # 戻り値「管理者に問い合わせてください」を設定する            ret = ErrMsg.UNKNOW            # エラーメッセージをログ出力する            self.output_log("%s(%s)" % (ret, self.err_msg))        # 戻り値を返す        return ret    def output_log(self, outp: str, inp: str = None):        ''' ログ出力する            Args:                self : 自分自身                inp  : 入力情報                outp : 出力情報            Returns:                None        '''        # ログファイルが存在し、書き込み不可の場合        if (os.path.exists(self.log_filename) and           (not os.access(self.log_filename, os.W_OK))):            # 何もしない            pass        # ログファイルが存在しない、あるいは書き込み可能な場合        else:            # ログファイルを開く            with open(self.log_filename, "a", encoding="utf-8") as self.fn:                # 現在時刻を取得する                now_time = datetime.datetime.now()                # 取得した現在時刻を出力の型式に変換する                tm = now_time.strftime("%Y/%m/%d %H:%M:%S")                # 入力情報が設定されてない場合                if (inp is None):                    # ログファイルに現在時刻、出力情報を出力する                    self.fn.write("%s %s\n" % (tm, outp))                # 入力情報が設定されている場合                else:                    # ログファイルに現在時刻、入力情報、出力情報を出力する                    self.fn.write("%s %s: %s\n" % (tm, inp, outp))        return</pre>
]]>
</description>
<link>https://ameblo.jp/masa-monty/entry-12964431088.html</link>
<pubDate>Tue, 28 Apr 2026 15:45:15 +0900</pubDate>
</item>
<item>
<title>SQL</title>
<description>
<![CDATA[ <p>「データベースは難しい」訳ではありません</p><p>でも、これからの説明は今までよりも「難しいな…」と感じるかもしれません</p><p>&nbsp;</p><p>私なりに理由を考えてみました</p><p>&nbsp;</p><p>１つ目は「知らなければならないことが増える」からだと思います</p><p>そして「知るための努力」をしなければならないからだと思います</p><p>「知るための努力」は「勉強」と言うよりは「調査」だと思います</p><p>最近はWebでいろいろと調べられるので、とても便利です</p><p>慌てないで１つずつ調べていけば良いのです</p><p>&nbsp;</p><p>２つ目は「何をしなければならないのか？」を（「段階を追って」）考えることが</p><p>なかなか大変な作業だからです</p><p>焦らずに、業務などを通じて経験値を増やしていけば大丈夫です</p><p>&nbsp;</p><p>まずはデータベースの知識を増やしましょう</p><p>データベースを利用するには、データベースがなければならないですよね</p><p>既存のデータベースを利用するには、</p><p>データベースのある場所を知らなければなりませんよね</p><p>今回はデータベースがありません</p><p>なので、まずは「データベースを作成する」ことです</p><p>ほんの少しだけ具体的に言えば、</p><p>データベースとは「情報基地」ですから「基地を作って、その中にデータを入れる」</p><p>ことが「データベース」を作成することになりますよね</p><p>&nbsp;</p><p>データベースを作成するには、どうすれば良いでしょうか？</p><p>データベースを作成するツール（ソフトウェア）を利用すれば良いです</p><p>世の中にはいくつかの優れたデータベースソフトが提供されています</p><p><a href="https://ja.wikipedia.org/wiki/MySQL" rel="noopener noreferrer" target="_blank">MySQL</a>や<a data-ved="2ahUKEwioo8KMqI-UAxUHQPUHHV_IAEIQFnoECD0QAQ" href="https://ja.wikipedia.org/wiki/PostgreSQL" jsname="UWckNb" ping="/url?sa=t&amp;source=web&amp;rct=j&amp;opi=89978449&amp;url=https://ja.wikipedia.org/wiki/PostgreSQL&amp;ved=2ahUKEwioo8KMqI-UAxUHQPUHHV_IAEIQFnoECD0QAQ">PostgreSQL</a>がその代表格です</p><p>これらのデータベースを利用しても良いのですが、</p><p>インストールなどに手間がかかり、それだけで嫌になってしまうので、</p><p>Pythonの<a href="https://docs.python.org/ja/3/library/sqlite3.html" rel="noopener noreferrer" target="_blank">sqlite3</a>ライブラリを利用します</p><p>※sqlite3をコマンドラインで利用するにはsqlite3ソフトをインストールする必要が</p><p>　ありますが、それは、またの機会にしましょう</p><p>&nbsp;</p><p><a href="https://ja.wikipedia.org/wiki/MySQL" rel="noopener noreferrer" target="_blank">MySQL</a>や<a data-ved="2ahUKEwioo8KMqI-UAxUHQPUHHV_IAEIQFnoECD0QAQ" href="https://ja.wikipedia.org/wiki/PostgreSQL" jsname="UWckNb" ping="/url?sa=t&amp;source=web&amp;rct=j&amp;opi=89978449&amp;url=https://ja.wikipedia.org/wiki/PostgreSQL&amp;ved=2ahUKEwioo8KMqI-UAxUHQPUHHV_IAEIQFnoECD0QAQ">PostgreSQL</a>には「<a href="https://ja.wikipedia.org/wiki/SQL" rel="noopener noreferrer" target="_blank">SQL</a>」という単語が含まれています</p><p>SQL(Structured Query Language：構造化照会言語(直訳だと理解できない…)）は、</p><p>データベース言語です</p><p>多くのデータベースで使える「共通の言語」ですので便利ですよね</p><p>&nbsp;</p><p>このSQL言語を利用するとデータベースへのアクセス（定義とか操作など）が容易に</p><p>なりますので、利用していきましょう</p><p>&nbsp;</p><p>今回、まず、必要になるのは「データベースの作成」です</p><p>データベースの作成するSQL文は以下になります</p><p>&nbsp;</p><p>　CREATE DATABASE IF NOT EXISTS&nbsp;employee.db</p><p>&nbsp;</p><p>「CREATE DATABASE」で社員データベース(employee.db)を作成できます</p><p>「IF NOT EXISTS」はなくても良いのですが、</p><p>対象となるデータベース(今回はemployee.db)がなければ作成するという意味で、</p><p>記述しておくと良いでしょう</p><p>※記述しないと、データベースがあった場合に失敗します</p><p>&nbsp;</p><p>データベースの作成することはできそうですが、それだけでは使えません</p><p>「情報基地」に「情報」を無造作に置けませんし、置けたとしても、どこに何が</p><p>あるのかわからない状態では使い物になりません</p><p>実際のデータを置く場所を「テーブル」といいます</p><p>いくつかのテーブルを設けて、データを置いていくと使いやすいですよね</p><p>今回は以下の３つのテーブルを作成することにします</p><p>・社員テーブル</p><p>・社員趣味テーブル</p><p>・社員特技テーブル</p><p>テーブルを作成するＳＱＬ文は以下になります</p><p>&nbsp;</p><p>　社員テーブル（tbl_employee）</p><p>　CREATE TABLE IF NOT EXISTS tbl_employee(</p><p>　&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; no INTEGER PRIMARY KEY,</p><p>　&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name TEXT,</p><p>　&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; birth TEXT,</p><p>　&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sex TEXT)</p><p>&nbsp;</p><p>　社員趣味テーブル（tbl_employee_hobby）</p><p>　CREATE TABLE IF NOT EXISTS tbl_employee_hobby(</p><p>　&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; id INTEGER PRIMARY KEY AUTOINCREMENT,</p><p>　&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; no INTEGER,</p><p>　&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; hobby TEXT)</p><p>&nbsp;</p><p>　社員特技テーブル（tbl_employee_hobby）</p><p>　CREATE TABLE IF NOT EXISTS tbl_employee_skill(</p><p>　&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; id INTEGER PRIMARY KEY AUTOINCREMENT,</p><p>　&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; no INTEGER,</p><p>　&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; skill TEXT)</p><p>&nbsp;</p><p>データベースの作成もそうでしたが、作成するときは「CREATE」なんですね</p><p>「IF NOT EXISTS」の説明もデータベースの作成と同様です</p><p>その後にテーブル名を記述して()内に情報を羅列していけば良いです</p><p>テーブル内の情報の名称を「フィールド」または「カラム」と呼びます</p><p>テーブル名もそうですけどフィールド名(カラム名)もSQL文内でアクセス（例えば</p><p>取得）する際に使用されます</p><p>&nbsp;</p><p>フィールド名の後にデータの種類（型：タイプ）を指定します</p><p>データの種類はたくさんありますが、今回は整数(INTEGER)と文字列(TEXT)の２つを</p><p>使用しています</p><p>&nbsp;</p><p>「PRIMARY KEY」は主キーです</p><p>主キーというのは、テーブル内の情報を一意に定めることのできるフィールド(カラム)</p><p>だと考えてよいです</p><p>主キーに指定するフィールド(カラム)はテーブルに１つ定義するものだと考えてよい</p><p>です</p><p>（主キーについて「考えてよいです」と記述した理由は機会があったら説明します）</p><p>&nbsp;</p><p>社員テーブルの主キーは社員番号としました</p><p>社員名を主キーにしたいところですが、文字列型を主キーにすることができません</p><p>工夫すれば何とかなるのですけれど、今回は社員番号を主キーとしました</p><p>※社員番号（社員コード）などは主キーにしやすいです</p><p>&nbsp;</p><p>社員趣味テーブルと社員特技テーブルは社員番号を主キーにすることができません</p><p>社員によっては複数の趣味や特技を持っている人がいるので、社員番号が複数に</p><p>なってしまうからです</p><p>なので、ほかの主キーを作成する必要があります</p><p>idと言うフィールド(カラム)を設けて主キーとすることにしました</p><p>このフィールドは実際のプログラムでは不要な項目になります</p><p>なので、プログラム内で設定する必要はないですよね</p><p>その場合は「PRIMARY KEY」の後に「 AUTOINCREMENT」と記述すると、</p><p>データベースがidを自動的に割り振ってくれます</p><p>&nbsp;</p><p>テーブルを作成しても、テーブルの上には何も置いてありません</p><p>テーブルの上に物(情報)を置いていく(格納する)には以下のSQL文を利用します</p><p>&nbsp;</p><p>　社員テーブル（tbl_employee）</p><p>　INSERT INTO tbl_employee VALUES ('{0}', '{1}', '{2}', '{3}')</p><p>　　{0}：社員番号(2601や2602など)</p><p>　　{1}：社員名(鈴木一郎や山田花子など)</p><p>　　{2}：生年月日(1974/02/09や1992/03/31など)</p><p>　　{3}：性別(男や女)</p><p>&nbsp;</p><p>　社員趣味テーブル（tbl_employee_hobby）</p><p>　INSERT INTO tbl_employee_hobby (no, hobby) VALUES ('{0}', '{1}')</p><p>　　{0}：社員番号(2601や2602など)</p><p>　　{1}：趣味(料理やキャンプなど)</p><p>&nbsp;</p><p>　社員特技テーブル（tbl_employee_skill）</p><p>　INSERT INTO tbl_employee_skill (no, skill) VALUES ('{0}', '{1}')</p><p>　　{0}：社員番号(2601や2602など)</p><p>　　{1}：特技(野球やピアノなど)</p><p>&nbsp;</p><p>「INSERT INTO」の後にテーブル名を記述しその後に()内に情報を格納するフィールド(カラム)をカンマ区切りで記述します</p><p>その後に「VALUES」を記述して()内にフィールド(カラム)に対応する情報をカンマ</p><p>区切りで記述します</p><p>各情報はシングルクォーテーションで囲みます</p><p>&nbsp;</p><p>社員テーブルのようにすべての情報を格納する場合はフィールド(カラム)リストを</p><p>省略できます</p><p>&nbsp;</p><p>データベースから情報を取得するSQL文は以下になります</p><p>&nbsp;</p><p>　社員テーブル（tbl_employee）</p><p>　SELECT * FROM tbl_employee WHERE no = '{0}'</p><p>　　{0}：社員番号(2601や2602など)</p><p>&nbsp;</p><p>　社員趣味テーブル（tbl_employee_hobby）</p><p>　SELECT hobby&nbsp;FROM tbl_employee_hobby WHERE no = '{0}'</p><p>　　{0}：社員番号(2601や2602など)</p><p>&nbsp;</p><p>　社員特技テーブル（tbl_employee_skill）</p><p>　SELECT skill&nbsp;FROM tbl_employee_skill WHERE no = '{0}'</p><p>　　{0}：社員番号(2601や2602など)</p><p>&nbsp;</p><p>取得コマンドは「SELECT」です</p><p>社員情報はすべての情報を取得するので「SELECT」の後に「*」を記述します</p><p>※社員番号は取得しなくても良いのですけど、１つくらい余分でも良いと思います</p><p>その後に「FROM」を記述し、続いて取得する情報のテーブル名を記述します</p><p>「WHERE」で取得する条件を記述できます</p><p>指定した社員番号の情報を取得するようにします</p><p>&nbsp;</p><p>社員趣味テーブル、社員特技テーブルも同様ですが、趣味(hobby)、特技(skill)のみを</p><p>取得するようにします</p><p>「SELECT」の後にフィールド名を記述すれば良いです</p><p>&nbsp;</p><p>これで、今回、利用するSQL文が揃いました</p><p>何事もそうですが「段取り」は大切ですよね</p><p>「段取り八分」とはよく言ったもので、準備をしっかりすれば後はプログラムを</p><p>作るだけです</p><p>&nbsp;</p>
]]>
</description>
<link>https://ameblo.jp/masa-monty/entry-12964414697.html</link>
<pubDate>Tue, 28 Apr 2026 14:10:35 +0900</pubDate>
</item>
<item>
<title>データベースの概念</title>
<description>
<![CDATA[ <p>社員リストをファイル形式で保有するのもありなのですが、「情報を管理をする」には</p><p>あまりよろしくありません</p><p>・csv型式のファイルもjson型式のファイルでもデータの型式が明確に定義されません</p><p>　でした。json型式のファイルでは文字列と数値の区別くらいは出来たのですけど、</p><p>　数値では範囲（例えば年齢なら0～150歳くらい）とかが決められませんでした</p><p>　（pythonではあまり関係ないのですけど、）数値情報は取り得る範囲で情報の入れ物</p><p>　のサイズ（情報量）を決めて効率よく管理するほうが良いです</p><p>　※現在はメモリとかディスクの容量が潤沢なのですが、昔は少なくて、効率化</p><p>　　しないとだめだったのです</p><p>・情報量が多くなってくるとファイルサイズが大きくなるだけでなく、ファイル内の</p><p>　情報を探す効率が悪くなります</p><p>　※複数ファイルに分割した時には情報の重複とかも注意しなければなりません</p><p>・複数のプログラムで情報を共有する場合に、同時に情報を変更したりすると、</p><p>　つじつまが合わなくなる可能性があります</p><p>&nbsp;</p><p>ここまで言っておいて何ですが、ファイルで情報を管理することは、別に悪いこと</p><p>ではありません。大切なのは考え方だと思います</p><p>データベースを利用しても、正しく情報の管理ができなければ意味がありませんし、</p><p>ファイルを利用して、正しく情報の管理ができれば問題ありません</p><p>&nbsp;</p><p>それでも、データベースを使う理由は、情報を管理しやすくなるからです</p><p>&nbsp;</p><p>情報の持ち方について、考えてみましょう</p><p>社員情報を以下のようにします</p><p>&nbsp;</p><table border="3"><caption>社員情報</caption><tbody><tr><th>氏名</th><th>生年月日</th><th>性別</th><th>趣味</th><th>特技</th></tr><tr><td>鈴木一郎</td><td align="center">1974/02/09</td><td align="center">男</td><td>&nbsp;</td><td>野球</td></tr><tr><td>山田花子</td><td align="center">1992/03/31</td><td align="center">女</td><td>料理</td><td>ピアノ</td></tr><tr><td>佐藤翠</td><td align="center">2008/11/23</td><td align="center">女</td><td>キャンプ</td><td>&nbsp;</td></tr><tr><td>高橋湊</td><td align="center">2000/07/10</td><td align="center">男</td><td>&nbsp;</td><td>&nbsp;</td></tr><tr><td>伊藤陽菜</td><td align="center">2000/12/24</td><td align="center">女</td><td>水泳、ゴルフ</td><td>料理</td></tr><tr><td>渡辺謙</td><td align="center">1970/04/05</td><td align="center">男</td><td>料理</td><td>キャンプ、釣り</td></tr></tbody></table><p>この形のままで情報を持つと趣味や特技のない人の領域をもたなければならなく</p><div>なります、社員が多くなってくると無駄な領域が増えてきますよね</div><div>なので、情報を分割してみましょう</div><div>&nbsp;</div><table border="3"><caption>社員情報</caption><tbody><tr><th>氏名</th><th>生年月日</th><th>性別</th></tr><tr><td>鈴木一郎</td><td align="center">1974/02/09</td><td align="center">男</td></tr><tr><td>山田花子</td><td align="center">1992/03/31</td><td align="center">女</td></tr><tr><td>佐藤翠</td><td align="center">2008/11/23</td><td align="center">女</td></tr><tr><td>高橋湊</td><td align="center">2000/07/10</td><td align="center">男</td></tr><tr><td>伊藤陽菜</td><td align="center">2000/12/24</td><td align="center">女</td></tr><tr><td>渡辺謙</td><td align="center">1970/04/05</td><td align="center">男</td></tr></tbody></table><table border="3"><caption>趣味情報</caption><tbody><tr><th>氏名</th><th>趣味</th></tr><tr><td>山田花子</td><td>料理</td></tr><tr><td>佐藤翠</td><td>キャンプ</td></tr><tr><td>伊藤陽菜</td><td>水泳、ゴルフ</td></tr><tr><td>渡辺謙</td><td>料理</td></tr></tbody></table><table border="3"><caption>特技情報</caption><tbody><tr><th>氏名</th><th>特技</th></tr><tr><td>鈴木一郎</td><td>野球</td></tr><tr><td>山田花子</td><td>ピアノ</td></tr><tr><td>伊藤陽菜</td><td>料理</td></tr><tr><td>渡辺謙</td><td>キャンプ、釣り</td></tr></tbody></table><div>&nbsp;</div><div>趣味や特技が２つ以上ある方がいますよね</div><div>この情報を取得した後で分割しなければならないので、ひと手間必要になります</div><div>たいていのデータベースには便利な機能があって、同じ趣味がある方や、同じ特技がある方をまとめて取得できる機能があります</div><div>なので、複数の趣味や特技を分けて持つようにしてみましょう</div><div>&nbsp;</div><table border="3"><caption>社員情報</caption><tbody><tr><th>氏名</th><th>生年月日</th><th>性別</th></tr><tr><td>鈴木一郎</td><td align="center">1974/02/09</td><td align="center">男</td></tr><tr><td>山田花子</td><td align="center">1992/03/31</td><td align="center">女</td></tr><tr><td>佐藤翠</td><td align="center">2008/11/23</td><td align="center">女</td></tr><tr><td>高橋湊</td><td align="center">2000/07/10</td><td align="center">男</td></tr><tr><td>伊藤陽菜</td><td align="center">2000/12/24</td><td align="center">女</td></tr><tr><td>渡辺謙</td><td align="center">1970/04/05</td><td align="center">男</td></tr></tbody></table><table border="3"><caption>趣味情報</caption><tbody><tr><th>氏名</th><th>趣味</th></tr><tr><td>山田花子</td><td>料理</td></tr><tr><td>佐藤翠</td><td>キャンプ</td></tr><tr><td>伊藤陽菜</td><td>水泳</td></tr><tr><td>伊藤陽菜</td><td>ゴルフ</td></tr><tr><td>渡辺謙</td><td>料理</td></tr></tbody></table><table border="3"><caption>特技情報</caption><tbody><tr><th>氏名</th><th>特技</th></tr><tr><td>鈴木一郎</td><td>野球</td></tr><tr><td>山田花子</td><td>ピアノ</td></tr><tr><td>伊藤陽菜</td><td>料理</td></tr><tr><td>渡辺謙</td><td>キャンプ</td></tr><tr><td>渡辺謙</td><td>釣り</td></tr></tbody></table><div>&nbsp;</div><div>社員情報、趣味情報、特技情報それぞれに「氏名」という項目があって、かえって「情報が増えているのでは？」と思う人もいますよね</div><div>&nbsp;</div><div>実はそうです</div><div>情報量が少ない場合は、わざわざ情報を分割して持たなくても良いのです</div><div>&nbsp;</div><div>ただ、情報っていろいろ分析したりしたい場合がありますよね</div><div>例えば、同じ趣味や同じ特技のある社員を探したい場合などです</div><div>この場合は、特技を分割しておいたほうが良さそうです</div><div>※最近のデータベース、分割しなくても探せたりするので説得力ないですけど…</div><div>　まぁ、情報の持たせ方の基本的な考え方です</div><div>&nbsp;</div><div>余談</div><div>　「コード」の概念が難しくなっている今日この頃です</div><div>　例えば「社員コード」ですが「社員名」でもいいのでは？と考えています</div><div>　昔は（最近、この言葉、多くなってきたな…）漢字などの２バイト文字を気軽に</div><div>　取り扱うことができませんでした</div><div>&nbsp;</div><div>　当然、ディスク容量とかもあります</div><div>　例えば「鈴木一郎」さんを「100」と言うコードで表現すれば、</div><div>　８バイト（「４文字×２バイト」）が１バイトで済みます</div><div>　ですが、現在はハードディスクの容量などから情報の大きさを気にしなくても</div><div>　よくなってきました</div><div>　データを圧縮して保持できるデータベースもあります</div><div>&nbsp;</div><div>　「コードとして持たせるか（コード化するか）？」は業務次第ですかね…</div><div>　※コードに意味を持たせると、なかなか素敵になる場合もあります</div><div>　　例えば社員コードに入社年月日を含めておけば「入社年月日」を社員コードから</div><div>　　判断できたり「入社年」が同じ社員を検索できたりします</div><div>&nbsp;</div>
]]>
</description>
<link>https://ameblo.jp/masa-monty/entry-12964314261.html</link>
<pubDate>Mon, 27 Apr 2026 12:16:11 +0900</pubDate>
</item>
<item>
<title>演習問題－２</title>
<description>
<![CDATA[ <p>何かを入力したら、それに対応する情報を出力するプログラムを作成してください</p><p>以下を必須とします</p><p>・仕様を提示すること</p><p>・単体テストを実施すること</p><p>・カバレッジ測定を実施すること</p><p>・テスト報告書を提示すること</p><p>・操作ログを提示すること</p><p>&nbsp;</p><p>問題を考えるのが面倒なので手を抜いている訳ではありません…</p><p>たぶん違う、違うんじゃないかな、少しくらいは…</p><p>&nbsp;</p><p>図工とかって何を作るのか決められてないことも多いじゃないですか！　</p><p>みなさんの発想に期待したいです</p><p>&nbsp;</p><p>それに、決められたことだけ作業するのってつまらないですよね</p><p>実際の業務では、決められた通りに作らなければならないですからね…</p><p>（決められた中で工夫して「どうよ！」っていうのも楽しいですけど…）</p><p>&nbsp;</p><p>でも、あまり頑張りすぎると、挫折しますので、ほどほどの発想でお願いします</p><p>よろしくです</p><p>&nbsp;</p>
]]>
</description>
<link>https://ameblo.jp/masa-monty/entry-12964025152.html</link>
<pubDate>Fri, 24 Apr 2026 17:28:18 +0900</pubDate>
</item>
<item>
<title>対話式</title>
<description>
<![CDATA[ <p>ここまでできたので、もう少し便利に使えるようにしましょう</p><p>&nbsp;</p><p>演習問題１では</p><p>コマンドの引数で社員番号を指定していました</p><p>それゆえ、複数の社員の情報を取得したい場合は、毎回、引数を指定して呼び出す</p><p>必要があります</p><p>ちょっと面倒なので、キーボードから入力できるようにします</p><p>&nbsp;</p><p>キーボードのことを標準入力といいます</p><p>画面のことを標準出力と呼んでいました（特に説明してませんでしたけど…）</p><p>&nbsp;</p><p>横道に逸れてしまいますが…</p><p>厳密に言うと、標準入力とか標準出力は違うかもしれません</p><p>「標準」の意味は…、難しいですね…、</p><p>コンピュータの世界では「一般的な」でしょうか…</p><p>そう考えると以下のようになりますね</p><p>　標準入力：コンピュータではキーボード</p><p>　標準出力：コンピュータではディスプレイ</p><p>でもですね…</p><p>タブレットとかではキーボードが「標準装備」されてないですので、タッチパネルが</p><p>標準入力ですよね…</p><p>また、常にファイルに出力するなら（画面には表示されないので）「ファイル」が</p><p>標準出力ですよね…、プリンタが標準出力になるかもしれません</p><p>てな感じですので、標準入力とか標準出力と言う言葉が使われたら「一般的に」</p><p>対象となる装置の中で、入出力できる（される）場所（キーボードとか画面とか）と</p><p>考えれば良いです</p><p>※１つだけ憶えておきたい用語があります</p><p>　「標準エラー出力」と呼ばれるものなのですけど、エラーの出力先になります</p><p>　パソコンなどは「標準出力」も「標準エラー出力」もディスプレイになってます</p><p>　ので、目視では両者の区別ができないです</p><p>&nbsp;</p><p>　pythonでよく利用されるログ記録用の<a href="https://docs.python.org/ja/3/library/logging.html" rel="noopener noreferrer" target="_blank">logging</a>というモジュールがあります</p><p>　このモジュールの場合は「標準エラー出力(stderr)」がデフォルトになります</p><p>　<a href="https://docs.python.org/ja/3/library/logging.html" rel="noopener noreferrer" target="_blank">logging</a>モジュールが「エラー発生時のログ」を想定しているからだと思います</p><p>　もし「標準出力」「標準エラー出力」の装置が異なっていた場合は、「標準出力」</p><p>　の装置ではログが確認できないので「標準エラー出力」の装置を見なければ</p><p>　なりません</p><p>　（標準入力と標準エラー出力の装置が異なる場合は、そうそうありませんが…）</p><p>&nbsp;</p><p>　おまけ</p><p>　　以下のキーワードが使用されることも多々あります</p><p>　　　標準入力：stdin</p><p>　　　標準出力：stdout</p><p>　　　標準エラー出力：stderr</p><p>&nbsp;</p><p>脱線し過ぎました…</p><p>キーボードで社員番号を入力するにはPython組み込みのinput関数を使用すれば</p><p>良いです</p><pre style="font-size: small">######################################################################## 主制御#                                                Copyrint 2026 Precede.#######################################################################from myproject.employee import Employee# =====================================================================# 関数# =====================================================================def main():    ''' 主制御        Args:            None        Returns:            None    '''    # ガイダンスを表示    print("'q'でプログラムを終了できます")    # 無限ループ    while (True):        # 入力待ち        emp_no: str = input("数字4桁の社員番号を入力してください: ")        # "q"が入力された場合        if emp_no == 'q':            # 無限ループを終了            break        # 社員番号を表示する        print(emp_no)        # 社員クラスのインスタンス生成        employee = Employee()        # 社員情報を取得する        msg: str = employee.get(emp_no)        # 社員情報を表示する        print(msg)    returnif __name__ == "__main__":    main()</pre><p>&nbsp;</p><p>引数を利用していないので引数を指定せずに起動します</p><p>（引数を指定しても起動しますが…）</p><p>&nbsp;</p><p>社員番号を入力してEnterキーを押すと社員情報が表示されます</p><p>小文字のqを入力してEnterキーを押すとプログラムが終了します</p><p>※説明は割愛しますが、まぁ、大丈夫でしょう…</p><p>　（決して「手抜き」ではありません…？）</p><p>&nbsp;</p><p><a href="https://stat.ameba.jp/user_images/20260424/17/masa-monty/b5/9b/p/o1920103215774805621.png"><img alt="" height="333" src="https://stat.ameba.jp/user_images/20260424/17/masa-monty/b5/9b/p/o1920103215774805621.png" width="620"></a></p><p>&nbsp;</p>
]]>
</description>
<link>https://ameblo.jp/masa-monty/entry-12964023857.html</link>
<pubDate>Fri, 24 Apr 2026 17:12:45 +0900</pubDate>
</item>
<item>
<title>戻り値</title>
<description>
<![CDATA[ <p>関数の最後にreturnという文を記述していました</p><p>returnだけ記述しても、何も起こらないのですけれど、retrunの後に値を記述すると</p><p>関数を呼び出したプログラム（呼び出し元）に値を返すことができます</p><p>&nbsp;</p><p>演習問題１のプログラムで値を返すようにしてみましょう</p><p>&nbsp;</p><p>employee.pyのoutputメソッドの名称をgetに変更します</p><p>呼び出し元に値を返すので、呼び出し元から見れば「値を取得する」ことになります</p><p>※関数名（メソッド名）は重要です</p><p>　outputでも良いような感じもありますがgetのほうがプログラムらしいです</p><p>print文で標準出力していた文字列をmsg変数に設定しておいて、msg変数をreturnの</p><p>後に記述します</p><p>&nbsp; &nbsp; def get(self, emp_no: str = None):<br>&nbsp; &nbsp; &nbsp; &nbsp; …<br>&nbsp; &nbsp; &nbsp; &nbsp; ''' 社員情報を標準出力する<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Args:<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self &nbsp; : 自分自身<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; emp_no : 社員番号<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Returns:<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; None<br>&nbsp; &nbsp; &nbsp; &nbsp; '''<br>&nbsp; &nbsp; &nbsp; &nbsp; # 標準出力メッセージ初期化<br>&nbsp; &nbsp; &nbsp; &nbsp; msg: str = ""<br>&nbsp; &nbsp; &nbsp; &nbsp; …<br>&nbsp; &nbsp; &nbsp; &nbsp; # メッセージを返す<br>&nbsp; &nbsp; &nbsp; &nbsp; return msg<br>&nbsp;</p><p>呼び出し元（main.pyのmain関数）ではget関数が返す値を変数に入れます</p><p>　&nbsp; &nbsp;&nbsp;msg: str = employee.get(emp_no)</p><p>そして、その値をprint文で標準出力するようにします</p><p>※今までと同じ標準出力にしたかったので、get関数の前に入力された社員番号も</p><p>　print文で標準出力するようにしています</p><pre>######################################################################## 主制御#                                                Copyrint 2026 Precede.#######################################################################import sysfrom myproject.employee import Employee# =====================================================================# 関数# =====================================================================def main():    ''' 主制御        Args:            None        Returns:            None    '''    # 引数の数が正しく設定されてない場合    if (len(sys.argv) != 2):        # 使い方を表示する        print("usage: python main.py emp_no")        print("         emp_no : 社員番号")    # 引数の数が正しく設定されている場合    else:        # 社員クラスのインスタンス生成        employee = Employee()        # 社員番号を設定する        emp_no = sys.argv[1]        # 社員番号を表示する        print(emp_no)        # 社員情報を取得する        msg: str = employee.get(emp_no)        # 社員情報を表示する        print(msg)    returnif __name__ == "__main__":    main()</pre><p>&nbsp;</p><p>何となくいい感じになりました</p><p>今回はこれで良いのですけど、もう少し勉強しましょう</p><p>&nbsp;</p><p>実はpythonは複数の値を返すことができます</p><p>returnの後、２つ目以降の値をカンマで区切って並べてあげれば良いです</p><p>※古い言語(?)（例えばC言語(?)）などでは１つだけしか返せなかったのです</p><p>　（最近のC言語の中には複数の値を返せるらしいですね…）</p><p>&nbsp;</p><p>社員番号と社員情報を戻り値に設定して、呼び出し元で表示するには以下のように</p><p>プログラムします</p><p>&nbsp;</p><p>employee.pyのgetメソッド</p><p>&nbsp; &nbsp; &nbsp; &nbsp; # 社員番号、社員番号を返す<br>&nbsp; &nbsp; &nbsp; &nbsp; return emp_no, msg</p><p>&nbsp;</p><p>呼び出し元（main.pyのmain関数）では戻り値の社員番号と社員情報を表示する</p><p>ようにします</p><pre>######################################################################## 主制御#                                                Copyrint 2026 Precede.#######################################################################import sysfrom myproject.employee import Employee# =====================================================================# 関数# =====================================================================def main():    ''' 主制御        Args:            None        Returns:            None    '''    # 引数の数が正しく設定されてない場合    if (len(sys.argv) != 2):        # 使い方を表示する        print("usage: python main.py emp_no")        print("         emp_no : 社員番号")    # 引数の数が正しく設定されている場合    else:        # 社員クラスのインスタンス生成        employee = Employee()        # 社員情報を取得する        emp_no, msg = employee.get(sys.argv[1])        # 社員番号を表示する        print(emp_no)        # 社員情報を表示する        print(msg)    returnif __name__ == "__main__":    main()</pre><p>&nbsp;</p><p>※複数の戻り値を返したいことは、多々あります</p><p>　昔のC言語などでは工夫して返していましたが、Pythonは工夫しなくても返せます</p><p>　なお、戻り値が複数の場合は型ヒント(: strのように変数の型の想定）を記述する</p><p>　ことができないようです</p><p>　「型ヒント」と呼ばれるくらいなので、記述しても実際には入力された値の型に</p><p>　なってしまいますが、プログラムを記述するときにはなるべく記述したほうが</p><p>　良いと思います（プログラム作成するときにも役に立つはずです）</p><p>　今回、あえて記述しようとするなら複数行で記述するのでしょうね…</p><p>&nbsp; &nbsp; &nbsp; &nbsp; emp_no: str = None</p><p>&nbsp; &nbsp; &nbsp; &nbsp; msg: str = None</p><p>&nbsp; &nbsp; &nbsp; &nbsp; emp_no, msg = employee.get(sys.argv[1])</p><p>　　※「 = None」は特に記述しなくても大丈夫です</p><p>&nbsp;</p>
]]>
</description>
<link>https://ameblo.jp/masa-monty/entry-12964015444.html</link>
<pubDate>Fri, 24 Apr 2026 15:39:46 +0900</pubDate>
</item>
<item>
<title>JSON</title>
<description>
<![CDATA[ <p><a href="https://ja.wikipedia.org/wiki/JSON" rel="noopener noreferrer" target="_blank">JSON</a>(JavaScript Object Notation)は<a href="https://ja.wikipedia.org/wiki/JavaScript" rel="noopener noreferrer" target="_blank">JavaScript</a> のデータ定義文でした…</p><p>「でした」という表現は正しくないですよね</p><p><a href="https://ja.wikipedia.org/wiki/JavaScript" rel="noopener noreferrer" target="_blank">JavaScript</a>の枠を超えて利用されているデータ定義文です</p><p>&nbsp;</p><p><a href="https://ja.wikipedia.org/wiki/Representational_State_Transfer" rel="noopener noreferrer" target="_blank">RESTful</a>&nbsp;APIで使用されているデータ定義文だと思い付くソフトウェア技術者も多いと</p><p>思います</p><p>JSONを利用する機会も少なくないので、演習問題１の入力ファイルをCSVからJSON</p><p>に変更してみます</p><p>&nbsp;</p><p>CVS形式の社員リストファイル(emplist.csv)の内容を現状のプログラムへの影響が</p><p>少ないようにJSON形式の社員リストファイル(emplist.json)に書き換えると以下の</p><p>ようになります</p><pre style="font-size: small">{    "0001": {        "name": "鈴木一郎",        "age": "52",        "sex": "男",        "skill": "野球"    },    "0002": {        "name": "山田花子",        "age": "34",        "sex": "女",        "hobby": "料理",        "skill": "ピアノ"    },    "0003": {        "name": "佐藤翠",        "age": "19",        "sex": "女",        "hobby": "キャンプ"    },    "0099": {        "name": "高橋湊",        "age": "27",        "sex": "男"    }}</pre><p>pythonの辞書型と似てますね</p><p>キーと値の組み合わせで記述します</p><p>文字列はダブルクォーテーションで囲みます</p><p>社員個々のデータは複数の要素を（{},）で区切ることにより記述できます</p><p>社員個々の中のデータは配列でも定義できますが、キー、値の型式で記述して</p><p>あります</p><p>プログラムを配列で取り扱う方法から、キーと値で取り扱う方法に変更したからで</p><p>この形式のほうがプログラムにとってはありがたいですし、一般的な記述方法に</p><p>「近い」からです</p><p>&nbsp;</p><p>プログラムで社員リストファイルから社員情報を読み込む箇所も変更します</p><p>&nbsp;</p><p>Pythonは<a href="https://docs.python.org/ja/3/library/json.html" rel="noopener noreferrer" target="_blank">json</a>ライブラリを組み込んであるのでインポートして使用します</p><p>　import json</p><p>&nbsp;</p><p>初期化処理（コンストラクタ）でファイル名（のプロパティ値）を変更します</p><p>　self.inp_filename: str = "emplist.json"</p><p>&nbsp;</p><p>jsonライブラリではファイルからjson形式の情報を読み込んで、辞書型に変換する</p><p>メソッドがあります</p><p>　self.emp_list: dict = json.load(fn)</p><p>&nbsp;</p><p>この修正だけで、既存のプログラムは動作します</p><p>&nbsp;</p><pre style="font-size: small">######################################################################## 社員クラス#                                                Copyrint 2026 Precede.#######################################################################…import json…class Employee:    def __init__(self):        ''' コンストラクタ            Args:                self : 自分自身            Returns:                None        '''        # エラーコード        self.err_msg: ErrMsg = None        # 社員リストファイル名        self.inp_filename: str = "emplist.json"        # ログファイル        self.log_filename: str = "employee.log"        # 社員リストファイルが存在する場合        if (os.path.exists(self.inp_filename)):            # 社員リストファイルが空の場合            if (os.path.getsize(self.inp_filename) == 0):                # エラーメッセージに「社員リストへの登録がありません」を設定する                self.err_msg = ErrMsg.LIST_EMPTY            # 社員リストファイルが空でない場合            else:                # 社員リストファイルを開く                with open(self.inp_filename, "r", encoding="utf-8") as fn:                    # 社員情報テーブルに格納する                    self.emp_list: dict = json.load(fn)        # 社員リストファイルが存在しない場合        else:            # エラーメッセージに「社員リストが見つかりません」を設定する            self.err_msg = ErrMsg.LIST_NOT_FOUND        return    …</pre><p>いい感じなんですが、用意した社員リストのJSONファイルは一般的な記述方法と</p><p>しては今一つです</p><p>「社員番号」が判断できないですよね</p><p>JSON形式は値が示す内容を判断できるようにするのが一般的です</p><p>（キーと値の組み合わせで情報を表現するのが普通です）</p><p>なので、以下のように記述することにします</p><p>"data"キーを最上位のキーにして、配列で社員情報を複数、持てるようにします</p><p>個々の社員情報は{}でひとまとまりの辞書型式とします</p><p>その中にキーと値を「キー:値」の型式で記述すれば良いです</p><p>今回は年齢は文字列でなく、数値で記述しました</p><p>（ダブルクォーテーションをとりました）</p><p>&nbsp;</p><pre style="font-size: small">{    "data": [        {            "no": "0001",            "name": "鈴木一郎",            "age": 52,            "sex": "男",            "skill": "野球"        },        {            "no": "0002",            "name": "山田花子",            "age": 34,            "sex": "女",            "hobby": "料理",            "skill": "ピアノ"        },        {            "no": "0003",             "name": "佐藤翠",            "age": 19,            "sex": "女",            "hobby": "キャンプ"        },        {            "no": "0099",             "name": "高橋湊",            "age": 27,            "sex": "男"        }    ]}</pre><p>&nbsp;</p><p>プログラムも修正が必要です</p><p>※「既存のプログラムに影響を与えないようにする」のはとても大切なのですが、</p><p>　「本来あるべき姿」でプログラムを作成することも大切です</p><p>　そして、どのような修正が適切かを判断できるようになると良いですね</p><p>　今回は「開発中」であることを想定して「本来あるべき姿」に修正します</p><p>&nbsp;</p><p>修正箇所は以下です</p><p>__init__</p><p>　ファイル名プロパティの設定値をJSONファイルにしました</p><p>　　self.inp_filename: str = "emplist.json"</p><p>　JSONファイルでは"data"キーに社員リスト情報が複数、記述されていますので、</p><p>　ファイルから読み込んで辞書型に変換した内容の'data'の中身をemp_listに格納</p><p>　するようにしています</p><p>　　self.emp_list: dict = json.load(fn)['data']</p><p>　※Pythonプログラム内では文字列はダブルクォーテーションでも大丈夫です</p><p>　　（self.emp_list: dict = json.load(fn)["data"]でもよいです）</p><p>&nbsp;</p><p>output</p><p>　社員番号が個々の社員情報の中に入っているので、社員情報を１行ずつ読み込んで</p><p>　入力された社員番号と一致するかを判断するようにしました</p><p>　社員番号に対する情報の有無を判定する変数を用意しました</p><p>　社員番号に対する情報が見つかった時に「社員情報あり」にして、</p><p>　繰り返しを抜けるようにしてます</p><p>　なお、年齢は数値データにしたので、文字列型に変換しています</p><p>　　str(emp['age'])</p><p>　str(変数名)で文字列型にできます</p><p>　「文字列型にキャストする」と呼びます</p><p>　※今回は使用してませんが「int()」とかもあります</p><p>&nbsp;</p><p>　# 社員不在</p><p>　flg_exist: bool = False</p><p>　for emp in self.emp_list:<br>&nbsp; &nbsp; 　if (emp_no == emp['no']):<br>&nbsp; &nbsp; &nbsp; &nbsp; 　# 標準出力メッセージに社員番号、社員名、年齢、性別を設定する<br>&nbsp; &nbsp; &nbsp; &nbsp; 　msg = emp_no + " " + \<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 　emp['name'] + \<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 　"(" + str(emp['age']) + ") " + \<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 　emp['sex']</p><p>　　　…<br>&nbsp; &nbsp; &nbsp; &nbsp; # 社員存在<br>&nbsp; &nbsp; &nbsp; &nbsp; flg_exist = True<br>&nbsp; &nbsp; &nbsp; &nbsp; # 繰り返しを抜ける<br>&nbsp; &nbsp; &nbsp; &nbsp; break<br>　# 社員番号が不在の場合&nbsp;</p><p>　if (not flg_exist):</p><p>　&nbsp; &nbsp; …</p><pre style="font-size: small">######################################################################## 社員情報#                                                Copyrint 2026 Precede.#######################################################################import datetimeimport enumimport jsonimport osclass ErrMsg(enum.StrEnum):    ''' エラーメッセージ        Args:            enum.StrEnum : 文字列列挙クラス        Returns:            None    '''    # 「社員リストが見つかりません」    LIST_NOT_FOUND = "No employee list."    # 「社員リストへの登録がありません」    LIST_EMPTY = "No one is registered on the employee list."    # 「社員番号がありません」    EMPLOYEE_NO_INVALID = "The employee number is invalid."    # 「社員番号が不正です」    EMPLOYEE_NO_NOT_FOUND = "Employee number not found."    # 「管理者に問い合わせてください」    UNKNOW = "Please contact your system administrator."class Employee:    ''' 社員情報        Args:            None        Returns:            None    '''    def __init__(self):        ''' コンストラクタ            Args:                self : 自分自身            Returns:                None        '''        # エラーコード        self.err_msg: ErrMsg = None        # 社員リストファイル名        self.inp_filename: str = "emplist.json"        # ログファイル        self.log_filename: str = "employee.log"        # 社員リストファイルが存在する場合        if (os.path.exists(self.inp_filename)):            # 社員リストファイルが空の場合            if (os.path.getsize(self.inp_filename) == 0):                # エラーメッセージに「社員リストへの登録がありません」を設定する                self.err_msg = ErrMsg.LIST_EMPTY            # 社員リストファイルが空でない場合            else:                # 社員リストファイルを開く                with open(self.inp_filename, "r", encoding="utf-8") as fn:                    # 社員情報テーブルに格納する                    self.emp_list: dict = json.load(fn)['data']        # 社員リストファイルが存在しない場合        else:            # エラーメッセージに「社員リストが見つかりません」を設定する            self.err_msg = ErrMsg.LIST_NOT_FOUND        return    def output(self, emp_no: str = None):        ''' 社員情報を標準出力する            Args:                self   : 自分自身                emp_no : 社員番号            Returns:                None        '''        # エラーメッセージが設定されてない場合        if (self.err_msg is None):            # 標準出力メッセージ初期化            msg: str = ""            # 社員不在            flg_exist: bool = False            # 社員番号が数値文字列、かつ、４桁の場合            if (emp_no.isdigit() and (len(emp_no) == 4)):                for emp in self.emp_list:                    if (emp_no == emp['no']):                        # 標準出力メッセージに社員番号、社員名、年齢、性別を設定する                        msg = emp_no + " " + \                            emp['name'] + \                            "(" + str(emp['age']) + ") " + \                            emp['sex']                        # 趣味特技なし                        flg_hobby_skill: bool = False                        # 趣味が登録されている場合                        if ('hobby' in emp):                            # "標準出力メッセージに&lt;趣味:xxx"を追加                            msg += " &lt;趣味:" + emp['hobby']                            # 趣味特技あり                            flg_hobby_skill = True                        # 特技が登録されている場合                        if ('skill' in emp):                            # 趣味が登録されてない場合                            if (not flg_hobby_skill):                                # 標準出力メッセージに"&lt;"を追加                                msg += " &lt;"                            # 趣味が登録されている場合                            else:                                # 標準出力メッセージに"/"を追加                                msg += "/"                            # 標準出力メッセージに"趣味:xxx"を追加                            msg += "特技:" + emp['skill']                            # 趣味特技あり                            flg_hobby_skill = True                        # 趣味特技ありの場合                        if (flg_hobby_skill):                            # 標準出力メッセージに"&gt;"を追加                            msg += "&gt;"                        # 社員存在                        flg_exist = True                        # 繰り返しを抜ける                        break                # 社員番号が不在の場合                if (not flg_exist):                    # 標準出力メッセージに「社員番号がありません」を設定する                    msg = ErrMsg.EMPLOYEE_NO_NOT_FOUND            # 社員番号が数値文字列以外、または、４桁でない場合            else:                # 標準出力メッセージに「社員番号が不正です」を設定する                msg = ErrMsg.EMPLOYEE_NO_INVALID            # 社員番号を標準出力する            print(emp_no)            # 社員情報を標準出力する            print(msg)            # ログ出力する            self.output_log(msg, emp_no)        # エラーメッセージが設定されている場合        else:            # 「管理者に問い合わせてください」を標準出力する            print(ErrMsg.UNKNOW)            # エラーメッセージをログ出力する            self.output_log("%s(%s)" % (ErrMsg.UNKNOW, self.err_msg))        return    def output_log(self, outp: str, inp: str = None):        ''' ログ出力する            Args:                self : 自分自身                inp  : 入力情報                outp : 出力情報            Returns:                None        '''        # ログファイルが存在し、書き込み不可の場合        if (os.path.exists(self.log_filename) and           (not os.access(self.log_filename, os.W_OK))):            # 何もしない            pass        # ログファイルが存在しない、あるいは書き込み可能な場合        else:            # ログファイルを開く            with open(self.log_filename, "a", encoding="utf-8") as self.fn:                # 現在時刻を取得する                now_time = datetime.datetime.now()                # 取得した現在時刻を出力の型式に変換する                tm = now_time.strftime("%Y/%m/%d %H:%M:%S")                # 入力情報が設定されてない場合                if (inp is None):                    # ログファイルに現在時刻、出力情報を出力する                    self.fn.write("%s %s\n" % (tm, outp))                # 入力情報が設定されている場合                else:                    # ログファイルに現在時刻、入力情報、出力情報を出力する                    self.fn.write("%s %s: %s\n" % (tm, inp, outp))        return</pre><p>&nbsp;</p><p>　※JSONファイルに変更した際の修正以外にも手を加えていますが、説明は割愛</p><p>　　させていただきます</p><p>&nbsp;</p><p>テストファイルもきれいにしてみました</p><p>unittestを行うときは初期化処理（__init__）を記述するとエラーになります</p><p>代替としてsetUpメソッドが用意されているので、オーバーライドしてください</p><p>※「オーバーライドしてください」の意味は</p><p>　「unittest.TestCaseのではなく自分のを使いたいから、setUpという同じ関数名を</p><p>　作ってください」です</p><p>主だった変更内容はそのくらいです</p><p>&nbsp;</p><pre style="font-size: small">######################################################################## 社員情報テスト#                                                Copyrint 2026 Precede.#######################################################################import osimport shutilimport statimport unittestfrom myproject.employee import Employeeclass TestEmployee(unittest.TestCase):    ''' 社員情報テスト        Args:            unittest.TestCase : テストケースクラス        Returns:            None    '''    def setUp(self):        ''' 初期化処理(unittestでは__init__の代替となっている)            Args:                self : 自分自身            Returns:                None        '''        # 社員リストファイル        self.inp_filename: str = "emplist.json"        # コピー元の社員リストファイル        self.src_inp_filename: str = "tests/emplist.json"        # コピー元の社員リストファイル（空ファイル）        self.src_inp_empty_filename: str = "tests/emplist_empty.json"        # ログファイル        self.log_filename: str = "employee.log"    def test_01_emlist_not_exist(self):        ''' 社員リストファイルがない場合            Args:                self : 自分自身            Returns:                None        '''        # 社員リストファイルが存在する場合        if (os.path.exists(self.inp_filename)):            # 社員リストファイルを削除する            os.remove(self.inp_filename)        # ログファイルが存在する場合        if (os.path.exists(self.log_filename)):            # ログファイルの読み取り専用を解除する            os.chmod(path=self.log_filename, mode=stat.S_IWRITE)            # ログファイルを削除する            os.remove(self.log_filename)        # 社員クラスインスタンス生成        employee = Employee()        # 社員番号0001        employee.output("0001")    def test_02_emplist_empty(self):        ''' 社員リストファイルが空の場合            Args:                self : 自分自身            Returns:                None        '''        # コピー元の社員リストファイル（空ファイル）を社員ファイルにコピーする        shutil.copy(self.src_inp_empty_filename, self.inp_filename)        # 社員クラスインスタンス生成        self = Employee()        # 社員番号0001        self.output("0001")    def test_03_argments(self):        ''' 通常動作            Args:                self : 自分自身            Returns:                None        '''        # コピー元の社員リストファイルを社員ファイルにコピーする        shutil.copy(self.src_inp_filename, self.inp_filename)        # 社員クラスインスタンス生成        self = Employee()        # 社員番号に英字が含まれている        self.output("a001")        # 社員番号に記号が含まれている        self.output("000!")        # 社員番号が3桁        self.output("001")        # 社員番号が5桁        self.output("00001")        # 社員番号0001        self.output("0001")        # 社員番号0002        self.output("0002")        # 社員番号0003        self.output("0003")        # 社員番号0004        self.output("0004")        # 社員番号0099        self.output("0099")    def test_04_logfile_readonly(self):        ''' ログファイルが読み取り専用の場合            Args:                self : 自分自身            Returns:                None        '''        # ログファイルを読み取り専用にする        os.chmod(path=self.log_filename, mode=stat.S_IREAD)        # 社員クラスインスタンス生成        self = Employee()        # 社員番号0001        self.output("0001")</pre><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p>
]]>
</description>
<link>https://ameblo.jp/masa-monty/entry-12963923868.html</link>
<pubDate>Thu, 23 Apr 2026 18:05:44 +0900</pubDate>
</item>
<item>
<title>例外について</title>
<description>
<![CDATA[ <p>例外についての考察です（個人的な考えですので、悪しからず）</p><p>&nbsp;</p><p>私は例外処理については否定的な考えを持っています…</p><p>いや、そうではないか…</p><p>「例外処理でなくても良い処理」も例外としてしまうことが好きではないのです</p><p>&nbsp;</p><p>例えば、ファイルが無かったときのFileNotFound例外ですが、ファイルを開く前に</p><p>ファイルの存在確認をすれば例外は発生しないのです</p><p>そして、osモジュールで確認できます（os.path.exists）</p><p>&nbsp;</p><p>でも、例外として取り扱ってほしい場合もあります</p><p>例えば、ハードディスクの破損など物理的な要因によりファイルが存在しないと</p><p>みなされる場合などが考えられます</p><p>この場合は例外が発生してほしいのですが、FileNotFound例外だと、あまり</p><p>うれしくないのです</p><p>（実際はどのような例外が発生するのかわかりませんが…）</p><p>もしかしたら、OS上ではあたかもファイルがあるように見えているかもしれません</p><p>（これも実際、どのような見え方になっているのかわかりません）</p><p>もし、見えているとしたら「ファイルがない」と言われても対処できないのです</p><p>&nbsp;</p><p>結局のところ、何が言いたいのかと言いますとですね…</p><p>プログラムを作成する人が極力、（前述のos.path.existsのように）プログラムの</p><p>「通常処理」として、例外処理をプログラムしないのが好みです</p><p>そして、理解できない例外の処理はOSとかPython(インタープリター)とかに任せて</p><p>しまうのが好みです</p><p>&nbsp;</p><p>私は</p><p>「考えられる例外（と言うかエラーとなる状況）は可能な限り考慮して、想定外の</p><p>　エラーの場合はプログラムでは捕まえない」</p><p>よう心がけています</p><p>&nbsp;</p><p>例えば、演習問題１ではログファイルを開くときに、PermissionError例外を捕まえて</p><p>いますが、事前にos.access(self.log_filename, os.W_OK)で書き込みできるかを確認</p><p>するよう記述できます</p><p>その他の例外は通常、発生しなさそうなので、例外処理を記述しないようにします</p><p>そうすると「例外」というあいまいな状況は考えなくてもよいことになります</p><p>（OSやPythonに任せてしまおうと考えます）</p><p>&nbsp;</p><p>なぜ、このようなことを言っているのかというと、</p><p>例外はいつ、どのような理由で発生するかわからないからです</p><p>演習問題１ではログファイルを開くときに、その他の例外（except Exception:）を</p><p>記述していますが、ここで捕えた例外がログファイルを開く処理をしたときに発生</p><p>する例外とは限らないからです</p><p>&nbsp;</p><p>演習問題１では、ほぼ、ログファイルを開くときに発生すると考えられますが、</p><p>もし、データベースからデータを読み込んで、ファイル出力する処理が記述されて</p><p>いたとすると、データベースへのアクセスで例外が発生することも考えられます</p><p>その場合でもその他の例外（except Exception:）の処理を通ることになります</p><p>かと言って、ファイル操作とデータベースのアクセスの例外を別々に記述すると</p><p>プログラムが煩雑になりそうですよね</p><p>&nbsp;</p><p>どこまで例外処理を記述すべきかはとても難しいです</p><p>（すべての関数やメソッドにtry～exceptを書いたれ！、</p><p>　と思ったこともありましたが、それはそれでねぇ…）</p><p>&nbsp;</p><p>ここまで記述しておいてですが、実は正解はありません</p><p>例外を利用するのが好きな方もいるでしょうし、いかなる例外が発生しようが、</p><p>プログラムを停止してはならないような場合は、先に述べたように、すべての</p><p>関数やメソッドに例外処理を記述すべきでしょう</p><p>&nbsp;</p><p>人の考え方は千差万別ですからね…</p><p>ご参考までに</p>
]]>
</description>
<link>https://ameblo.jp/masa-monty/entry-12963919614.html</link>
<pubDate>Thu, 23 Apr 2026 16:29:37 +0900</pubDate>
</item>
<item>
<title>カバレッジ測定</title>
<description>
<![CDATA[ <p>単体テストも行ったので、これで大丈夫…とはなかなかならないのが現実です</p><p>「それでは、どこまで確認すればいいの？」いい加減うんざりですよね</p><p>&nbsp;</p><p>「人は間違える生き物」ですからしかたないのです</p><p>でも、いろいろと間違えない工夫をしています</p><p>単体テストモジュール（unittest）もそうでした</p><p>（プログラムも含めて）機械に正確に実行してもらうようにすることで、間違いを</p><p>少なくしています</p><p>&nbsp;</p><p>１つのプログラム（演習問題では社員クラス）の確認は終了間近です</p><p>最後に残った課題は「単体テストが間違ってないか？」です</p><p>「確認項目」は「プログラムの分岐」に着目して作成しました</p><p>ということは、「確認項目」が「プログラムの分岐」をすべて通っているかが確認</p><p>できれば「確認項目」も正しいことになります</p><p>※標準出力、ログファイル出力の内容は目視で確認したということで、勘弁して</p><p>　もらいましょう（さもないと、エンドレスになってしまいます）</p><p>「プログラムの分岐」を確認することを「カバレッジ測定」といいます</p><p>「カバレッジ(coverage)は「適用範囲」と言う意味の単語です」</p><p>&nbsp;</p><p>余談</p><p>「カバレッジ測定」によってすべての分岐が通れば良いのですが、必ずしもそうは</p><p>ならない場合もあります</p><p>今回も「その他の例外」をプログラムしましたが、「その他の例外」を発生させる</p><p>要因を確認項目で実現するのは、かなり難しいです（できるかもしれませんが、</p><p>まず、発生しないであろう状況に時間を費やすのは現実的ではありません）</p><p>※実際の業務では、発生しないであろう例外などはプログラムに記述しない方針に</p><p>　してもらうと良いかもしれません</p><p>&nbsp;</p><p>pythonモジュールではカバレッジ測定を実行してくれるモジュールも用意して</p><p>あります（本当にすごいですね…）</p><p>&nbsp;</p><p>カバレッジモジュールはインストールすると使えるようになりますが、</p><p>Windows11ではセキュリティが強化されているので、インストールできるように</p><p>設定を変更しなければなりません</p><p>&nbsp;</p><p>Windowsキーを押すなどして「設定」を選択します</p><p><a href="https://stat.ameba.jp/user_images/20260423/11/masa-monty/28/f4/p/o0834086615774394468.png"><img alt="" height="436" src="https://stat.ameba.jp/user_images/20260423/11/masa-monty/28/f4/p/o0834086615774394468.png" width="420"></a></p><p>&nbsp;</p><p>「プライバシーとセキュリティ」を選択します</p><p><a href="https://stat.ameba.jp/user_images/20260423/11/masa-monty/c3/2a/p/o1024080115774394471.png"><img alt="" height="329" src="https://stat.ameba.jp/user_images/20260423/11/masa-monty/c3/2a/p/o1024080115774394471.png" width="420"></a></p><p>&nbsp;</p><p>「Windowsセキュリティ」を選択します</p><p><a href="https://stat.ameba.jp/user_images/20260423/11/masa-monty/b3/0a/p/o1024080115774394473.png"><img alt="" height="329" src="https://stat.ameba.jp/user_images/20260423/11/masa-monty/b3/0a/p/o1024080115774394473.png" width="420"></a></p><p>&nbsp;</p><p>「アプリとブラウザーの利用」を選択します</p><p><a href="https://stat.ameba.jp/user_images/20260423/11/masa-monty/2c/ea/p/o1024080115774394477.png"><img alt="" height="329" src="https://stat.ameba.jp/user_images/20260423/11/masa-monty/2c/ea/p/o1024080115774394477.png" width="420"></a></p><p>&nbsp;</p><p>「スマートアプリコントロールの設定」を選択します</p><p><a href="https://stat.ameba.jp/user_images/20260423/11/masa-monty/a4/91/p/o1024080115774394478.png"><img alt="" height="329" src="https://stat.ameba.jp/user_images/20260423/11/masa-monty/a4/91/p/o1024080115774394478.png" width="420"></a></p><p>&nbsp;</p><p>信頼されていないアプリからの保護の設定で「オフ」を選択します</p><p><a href="https://stat.ameba.jp/user_images/20260423/11/masa-monty/c0/ef/p/o1024080115774394480.png"><img alt="" height="329" src="https://stat.ameba.jp/user_images/20260423/11/masa-monty/c0/ef/p/o1024080115774394480.png" width="420"></a></p><p><a href="https://stat.ameba.jp/user_images/20260423/11/masa-monty/d9/aa/p/o1024080115774394483.png"><img alt="" height="329" src="https://stat.ameba.jp/user_images/20260423/11/masa-monty/d9/aa/p/o1024080115774394483.png" width="420"></a></p><p>&nbsp;</p><p>※カバレッジモジュールのインストールが終わったら（必要に応じて）「オン」に</p><p>　戻して置くと良いでしょう</p><p>&nbsp;</p><p>VSCodeに戻ってカバレッジモジュールのインストールをします</p><p>ターミナルを開いて、以下のコマンドを入力します</p><p>　pip install coverage</p><p>&nbsp;</p><p>pipはPythonのパッケージ管理モジュールで「python -m pip」と入力しなくても利用</p><p>できるようです</p><p>「pip install」でPythonのパッケージ（モジュール）をインストールします</p><p>ここではカバレッジ測定ツール(coverage)をインストールします</p><p><a href="https://stat.ameba.jp/user_images/20260423/13/masa-monty/57/9f/p/o1920103215774411686.png"><img alt="" contenteditable="inherit" height="333" src="https://stat.ameba.jp/user_images/20260423/13/masa-monty/57/9f/p/o1920103215774411686.png" width="620"></a><a href="https://stat.ameba.jp/user_images/20260423/10/masa-monty/75/2f/p/o1920103215774372753.png"><img alt="" contenteditable="inherit" height="333" src="https://stat.ameba.jp/user_images/20260423/10/masa-monty/75/2f/p/o1920103215774372753.png" width="620"></a></p><p>&nbsp;</p><p>以下のコマンドを投入してカバレッジ測定をしましょう</p><p>　python -m coverage run -m unittest discover -s tests</p><p>&nbsp;</p><p>「python -m」はユニットテストの時と同様で</p><p>「pythonでcoverageというモジュールを実行します」という内容になります</p><p>&nbsp;</p><p>coverageにはいくつかのサブコマンドがありrunコマンドでカバレッジ測定を実行</p><p>します</p><p>runのオプション「-m」で実行するモジュールを指定します</p><p>前回実行したunittestモジュールとその引数をそのまま記述すれば良いです</p><p><a href="https://stat.ameba.jp/user_images/20260423/13/masa-monty/55/c3/p/o1920103215774425559.png"><img alt="" contenteditable="inherit" height="333" src="https://stat.ameba.jp/user_images/20260423/13/masa-monty/55/c3/p/o1920103215774425559.png" width="620"></a></p><p>&nbsp;</p><p>実行結果は.coverageというファイルに保存されます</p><p>このファイルは<a href="https://ja.wikipedia.org/wiki/%E3%83%90%E3%82%A4%E3%83%8A%E3%83%AA" rel="noopener noreferrer" target="_blank">バイナリ</a>型式で出力されていますので、人が読むのには相当な鍛錬が</p><p>必要です</p><p>（なぜバイナリで出力されているのかは作者に聞かなければわかりませんが</p><p>　過去にファイルサイズとかの問題があったのかもしれません）</p><p>以下のコマンドでHTML型式に変換してくれます</p><p>　python -m coverage html</p><p><a href="https://stat.ameba.jp/user_images/20260423/14/masa-monty/29/da/p/o1920103215774429934.png"><img alt="" height="333" src="https://stat.ameba.jp/user_images/20260423/14/masa-monty/29/da/p/o1920103215774429934.png" width="620"></a></p><p>&nbsp;</p><p>htmlcovフォルダが作成されました</p><p>&nbsp;</p><p>フォルダ内にあるindex.htmlを右クリックして「プレビューの表示」を選択すると</p><p>ファイルの内容が表示されます</p><p><a href="https://stat.ameba.jp/user_images/20260423/14/masa-monty/31/ff/p/o1920103215774431547.png"><img alt="" height="333" src="https://stat.ameba.jp/user_images/20260423/14/masa-monty/31/ff/p/o1920103215774431547.png" width="620"></a></p><p>&nbsp;</p><p>社員クラス(employee.py)は98%、</p><p>社員クラスのテストモジュール(test_employee.py)は100%</p><p>となっていますね</p><p>リンクされているので開いてみましょう</p><p><a href="https://stat.ameba.jp/user_images/20260423/14/masa-monty/6d/ce/p/o1920103215774431548.png"><img alt="" height="333" src="https://stat.ameba.jp/user_images/20260423/14/masa-monty/6d/ce/p/o1920103215774431548.png" width="620"></a></p><p>&nbsp;</p><p>画面を大きくして（タブを移動させて）引き延ばしてみてみますと、</p><p>緑色で「72 run」、赤色「2 missing」となっています</p><p><a href="https://stat.ameba.jp/user_images/20260423/14/masa-monty/ff/0d/p/o1920103215774433548.png"><img alt="" height="333" src="https://stat.ameba.jp/user_images/20260423/14/masa-monty/ff/0d/p/o1920103215774433548.png" width="620"></a></p><p>&nbsp;</p><p>下のほうにスクロールすると、ログファイルが開けなかったときの例外の処理が</p><p>通らなかったことがわかります</p><p>この処理を通すのは難しそうです</p><p>※テスト報告書のエビデンスにカバレッジ測定結果も添付すべきですが、</p><p>　通らなかった箇所については、注釈を付け加えておくのが良いでしょう</p><p>　今回の場合は、例えば以下のような注釈が良いでしょう</p><p>　「ファイルを追加モードで開くとき、ファイルが存在して書き込み禁止のときの</p><p>　　例外は捕えることができるが、それ以外の例外は、通常運用では発生しない</p><p>　　（例外を１つでも記述した場合は、その他の例外も記述するという規則に</p><p>　　従って記述してある）」　</p><p><a href="https://stat.ameba.jp/user_images/20260423/14/masa-monty/04/a9/p/o1920103215774434530.png"><img alt="" height="333" src="https://stat.ameba.jp/user_images/20260423/14/masa-monty/04/a9/p/o1920103215774434530.png" width="620"></a></p><p>&nbsp;</p><p>社員クラスのテストモジュールは100%でしたので、ここでは割愛しています</p><p>なお、テストモジュールのカバレッジ結果は不要かもしれません</p><p>その場合はomitオプションを指定すると良いでしょう</p><p>　python -m coverage run --omit=tests/* -m unittest discover -s tests</p><p>&nbsp;</p>
]]>
</description>
<link>https://ameblo.jp/masa-monty/entry-12963892742.html</link>
<pubDate>Thu, 23 Apr 2026 12:06:51 +0900</pubDate>
</item>
</channel>
</rss>
