Pythonで自分がよく使うコードサンプル

## はじめに
Pythonで開発を始めて数か月たつが、コーディングを始めると過去のコードをあさったり、WEBで検索かけたりと、よく使うけど何度も調べているコードがたくさんあるので、自分なりにまとめておいた。

サンプル作るにあたり、入力データをAIに作ってもらった。
何気に面倒な作業なので、すごく楽で良い世の中になったものだと実感...

## サンプルコード
<details><summary>パス</summary>

```python
import os

# カレントディレクトリ
APP_PATH = os.getcwd()
# ファイルパス
FILE_PATH = os.path.dirname(__file__)
```
</details>


<details><summary>JSONファイルをdictに変換する</summary>

``` python: main.py
import os
import json

# カレントディレクトリ・ファイルパス
APP_PATH = os.getcwd()

# 定数定義
JSON_FILE = 'sample.json'
ENCORDING_UTF_8 = 'utf-8'
ENCORDING_SHIFT_JIS = 'shift_jis'

""" JSONファイルをdictに変換する """
json_path = os.path.join(APP_PATH, JSON_FILE)
with open(json_path, 'rt', encoding=ENCORDING_UTF_8) as json_file:
    json_data = json.load(json_file)

    # キーと値を取得してループする
    for key, value in json_data.items():
        print(f"{key}:")

        # キーを取得してループする(.keys()は省略可能)
        # ※値を取得したい場合は .values()で可能
        for sub_key in value.keys():
            print(f" - {sub_key}: {value[sub_key]}")
```

<details><summary>入力＆出力結果</summary>

``` json: sample.json
{
    "section1": {
        "description": "サンプルデータ1",
        "value": 1234
    },
    "section2": {
        "description": "サンプルデータ2",
        "value": 5678
    }
}
```

``` console:出力結果
section1:
 - description: サンプルデータ1
 - value: 1234
section2:
 - description: サンプルデータ2
 - value: 5678
```
</details>
</details>


<details><summary>dictをJSONファイルに変換して保存する</summary>

``` python: main.py
import os
import json

# カレントディレクトリ・ファイルパス
APP_PATH = os.getcwd()

# 定数定義
JSON_FILE = 'sample.json'
ENCORDING_UTF_8 = 'utf-8'
ENCORDING_SHIFT_JIS = 'shift_jis'

""" dictをJSONファイルに変換して保存する """
# 保存するデータ
dict_data = {
    "section1": {
        "description": "サンプルデータ1",
        "value": 1234,
    },
    "section2": {
        "description": "サンプルデータ2",
        "value": 5678,
    },
}

# dictをJSONファイルに変換して保存する
json_path = os.path.join(APP_PATH, JSON_FILE)
with open(json_path, 'wt', encoding=ENCORDING_UTF_8) as json_file:
    json.dump(dict_data, json_file, ensure_ascii=False, indent=2)
```
</details>


<details><summary>dictの指定データを抽出してソートする</summary>

``` python: main.py
import os
import json

# 定数定義
JSON_FILE = 'sample.json'

# カレントディレクトリ・ファイルパス
APP_PATH = os.getcwd()

# サンプルデータの読み込み
json_path = os.path.join(APP_PATH, JSON_FILE)
with open(json_path, 'rt', encoding=ENCORDING_UTF_8) as json_file:
    json_data = json.load(json_file)

# 年齢が 30歳以上の社員を抽出する
selected_data = [item for item in json_data if item['age'] >= 30]

# 抽出結果を年齢、名前で昇順にソートする
sorted_data = sorted(selected_data,
                     key=lambda x: (x['age'], x['name']))
for item in sorted_data:
    print(item)
```

<details><summary>入力＆出力結果</summary>

``` console: 入力データ（sample.jsonをdictに変換したもの）
{'name': '佐藤 太郎', 'age': 28, 'dpartment': '営業', 'yearOfJoining': 2020, 'email': 'taro.sato@example.com'}
{'name': '鈴木 花子', 'age': 32, 'dpartment': '人事', 'yearOfJoining': 2018, 'email': 'hanako.suzuki@example.com'}
{'name': '高橋 健一', 'age': 41, 'dpartment': '開発', 'yearOfJoining': 2010, 'email': 'kenichi.takahashi@example.com'}
{'name': '田中 美咲', 'age': 25, 'dpartment': 'マーケティング', 'yearOfJoining': 2022, 'email': 'misaki.tanaka@example.com'}
{'name': '山本 達也', 'age': 35, 'dpartment': '開発', 'yearOfJoining': 2012, 'email': 'tatsuya.yamamoto@example.com'}
{'name': '伊藤 翔', 'age': 35, 'dpartment': '財務', 'yearOfJoining': 2015, 'email': 'sho.ito@example.com'}
{'name': '渡辺 優子', 'age': 29, 'dpartment': '営業', 'yearOfJoining': 2019, 'email': 'yuko.watanabe@example.com'}
{'name': '中村 直子', 'age': 30, 'dpartment': '総務', 'yearOfJoining': 2017, 'email': 'naoko.nakamura@example.com'}
{'name': '小林 大輔', 'age': 45, 'dpartment': '経営企画', 'yearOfJoining': 2008, 'email': 'daisuke.kobayashi@example.com'}
{'name': '加藤 恵', 'age': 27, 'dpartment': 'デザイン', 'yearOfJoining': 2021, 'email': 'megumi.kato@example.com'}
```

``` console:出力結果
{'name': '中村 直子', 'age': 30, 'dpartment': '総務', 'yearOfJoining': 2017, 'email': 'naoko.nakamura@example.com'}
{'name': '鈴木 花子', 'age': 32, 'dpartment': '人事', 'yearOfJoining': 2018, 'email': 'hanako.suzuki@example.com'}
{'name': '伊藤 翔', 'age': 35, 'dpartment': '財務', 'yearOfJoining': 2015, 'email': 'sho.ito@example.com'}
{'name': '山本 達也', 'age': 35, 'dpartment': '開発', 'yearOfJoining': 2012, 'email': 'tatsuya.yamamoto@example.com'}
{'name': '高橋 健一', 'age': 41, 'dpartment': '開発', 'yearOfJoining': 2010, 'email': 'kenichi.takahashi@example.com'}
{'name': '小林 大輔', 'age': 45, 'dpartment': '経営企画', 'yearOfJoining': 2008, 'email': 'daisuke.kobayashi@example.com'}```
```
</details>
</details>


<details><summary>列挙型定義（Enum）</summary>

``` python: main.py
from enum import Enum, auto

# 列挙型定義
class WeekDay(Enum):
    Sunday = 0
    Monday = auto()
    Tuesday = auto()
    Wednesday = auto()
    Thursday = auto()
    Friday = auto()
    Saturday = auto()

# 列挙型定義の使い方
week_day = WeekDay.Monday
print(f"{week_day}")
print(f"name = {week_day.name}")
print(f"value = {week_day.value}")
```

<details><summary>出力結果</summary>

``` console:出力結果
WeekDay.Monday
name = Monday
value = 1
```
</details>
</details>


<details><summary>列挙型定義（IntEnum）</summary>

``` python: main.py
from enum import IntEnum, auto

# 列挙型定義
class WeekDay(IntEnum):
    Sunday = 0
    Monday = auto()
    Tuesday = auto()
    Wednesday = auto()
    Thursday = auto()
    Friday = auto()
    Saturday = auto()

# 列挙型定義の使い方
week_day = WeekDay.Monday
print(f"{week_day}")
print(f"name = {week_day.name}")
print(f"value = {week_day.value}")
```

<details><summary>出力結果</summary>

``` console:出力結果
1
name = Monday
value = 1
```
</details>
</details>


<details><summary>関数のオーバーロードっぽいもの</summary>

Pythonでは、C++のような関数のオーバーロード（引数の型によって異なる関数を自動で選ぶ）は標準では直接サポートされていませんが、いくつかの方法で型による処理の振り分けが可能です。
``` python: 方法①：isinstance() で型を判別する（もっとも基本的）
def process(value):
    if isinstance(value, str):
        print(f"文字列: {value}")
    elif isinstance(value, (int, float)):
        print(f"数値: {value}")
    else:
        print("未知の型")

process("hello")   # → 文字列
process(123)       # → 数値
process(3.14)      # → 数値
```

``` python: 方法②：functools.singledispatch を使った関数のオーバーロード風処理（推奨）
# C++風の関数オーバーロードに最も近い方法
# ただし「第1引数の型のみ」で分岐される点に注意（複数引数には対応しない）
from functools import singledispatch

@singledispatch
def process(value):
    print("デフォルト: 未知の型")

@process.register
def _(value: str):
    print(f"文字列: {value}")

@process.register
def _(value: int):
    print(f"整数: {value}")

@process.register
def _(value: float):
    print(f"浮動小数点: {value}")

process("test")  # → 文字列
process(10)      # → 整数
process(3.14)    # → 浮動小数点
```
</details>


<details><summary>クラス</summary>

<details><summary>プロパティ</summary>

``` python: main.py
def class Sample():
    @property
    def Visibled(self) -> bool:
        """ getter """
        return self.__visibled

    # ★プロパティ名.setter なので注意
    @Visibled.setter
    def Visibled(self, value: bool):
        """ setter """
        self.__visibled = value
```
</details>
</details>



<details><summary>コーディング規約</summary>

<details><summary>Python命名規則</summary>

|要素|命名規則|例|
|--|--|--|
|ファイル名|snake_case.py|my_module.py|
|クラス名|PascalCase|MyProcessor|
|関数名・変数名|snake_case|process_data()|
|定数名|UPPER_CASE|MAX_SIZE|
|プライベート|_snake_case|_helper_func()|

:::note info
関数・変数名は「動詞+目的語」の形が読みやすい
:::

</details>

<details><summary>参考リンク</summary>

・[Visual Studio CodeでPythonの自動校正を行う](https://qiita.com/HirumaT/items/16b87e55e9a5ed62ea6f)
・[【VSCode】flake8で特定エラーの警告を非表示にする](https://qiita.com/Maron_T/items/d0ea99faec8dd71ddfc0)
</details>

<details><summary>関数の引数と呼び出し元の変数名を変えたい</summary>

「関数の引数」と「呼び出し元の変数名」が同じだと、可読性やトレースのしやすさに影響を与えることがあるため避けたい。
解決策として、関数の外・中で変数名を変えて役割を明示してみる。

``` python: ■悪い例
def process_data(data):
    # data という変数が何を意味するのか曖昧になりやすい
    ...
    
data = load_data()
process_data(data)
# ここで「data」がずっと使われ続けると、
# 何のデータか？ 誰の責任範囲か？ が不明瞭になり良くない
```

``` python: ■良い例
def process_user_data(user_data):
    # 関数の引数は役割にそった汎用的な名前を付ける
...

# 関数の外では、具体的な名前を付ける
raw_data = load_data()
process_user_data(raw_data)
```
</details>
</details>


<details><summary>折りたたみ</summary>

VSCodeにて、任意の範囲で折り畳みができる（C#と同じ方法でできた）
　すべて折りたたむ → 「Ctrl + K」の後に「Ctrl + 0」
　すべて展開する　 → 「Ctrl + K」の後に「Ctrl + J」
``` python: 
# region コンストラクタ
def __init__(self):
    """
    コンストラクタ
    """
    self.__xlapp = None
    self.__visibled = True
# endregion
```
</details>


## 開発環境
### Visual Studio Code

<details><summary>起動時に前回の設定で立ち上がらないようにする</summary>

下記の設定をsetting.jsonに追記する。
``` command
"window.restoreWindows": "none",
```
</details>

<details><summary>ターミナル上で選択でコピー、右クリックでペーストする</summary>

下記の設定をsetting.jsonに追記する。
``` command
"terminal.integrated.copyOnSelection": true,
"terminal.integrated.rightClickBehavior": "copyPaste",
```
</details>

<details><summary>タイトルやアクティブバーの色を変える</summary>

デフォルト設定のままでは、ウィンドウの区切りがわかりづらいので色を変えてみる。下記の設定をUser用のsetting.jsonに追記する（Ctrl+Shift+P → 「Setting.json」を入力）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/683161/77145753-d43b-4086-b69e-1affbd92e0d4.png)

``` command
"workbench.colorCustomizations": {
    "titleBar.activeBackground": "#000070",     // タイトルバーの背景色
    "titleBar.activeForeground": "#FFFFFF",     // タイトルバーの文字色
    "statusBar.background": "#000070",          // ワークスペースを開いていない状態のステータスバー背景色
    "statusBar.foreground": "#FFFFFF",          // ワークスペースを開いていない状態のステータスバー前景色
    "statusBar.noFolderBackground": "#000070",  // フォルダーを開いていない状態のステータスバー背景色
    "activityBar.background": "#000070",        // アクティビティバーの背景色
    "activityBar.foreground": "#FFFFFF",        // アイコン
},
```
</details>

### PlantUML

<details><summary>インストール</summary>

<details><summary>OpenJDKのインストール</summary>

１．OpenJDKをダウンロードしてインストールする
　https://jdk.java.net/
　<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/683161/ca5bd31b-427a-4171-85c7-d5bf96e3fdd2.png">

２．zipファイルをダウンロードする
　<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/683161/432d6de3-466b-43ad-ac0e-afaa00911f28.png">

３．上記のzipファイルを任意の場所に解凍する
　<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/683161/431471e0-53db-4f5a-b631-1d8b13361f43.png">

４．環境変数 JAVA_HOMEを設定する。
　<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/683161/8d09a689-faad-4e62-8be8-c181ae94025a.png">

５．環境変数 PATHにOpenJDKのパスを追加する。
``` command
%JAVA_HOME%\bin
```
</details>

<details><summary>PlantUMLの拡張機能をインストール</summary>

Visual Studio Codeの拡張機能タブを選択し、「PlantUML」を入力してインストールする
　<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/683161/fe5fd0dd-ebd3-402f-b710-e9fd226c6776.png">
</details>

</details>