プロジェクト

全般

プロフィール

Python言語の書き方

プログラム(ツール)構成

最初に、Pythonで記述するプログラムの構成概要をまとめます。

ファイル

単独ファイルをスクリプトとして実行

Pythonはスクリプト言語なので、Pythonスクリプトを記述したファイルをそのまま指定して実行します。

python hello.py

スクリプトファイル先頭のShebang

UNIX系の環境で、シェルスクリプトのようにPythonスクリプトファイルを直接指定して実行したいときは、ファイルの先頭にShebangを記述します。

  1. #!/usr/bin/python
    システムの/usr/bin/python をPython実行コマンドとして実行
  2. #!/usr/bin/env python3
    envコマンドが、環境変数PATHから見つけたpython3を実行

venv等の仮想環境を使用する場合、activateした上で後者(/usr/bin/envを呼び出すShebang)を使用します。

Windows OS上

Windows環境で、PythonスクリプトファイルをExplorer上でダブルクリックして実行することも可能ですが、拡張子.pyがpython実行ファイルに関連付けされている必要があります。
.pyファイルを右クリック、[プロパティ] > [全般]タブ > ファイルの種類欄でプログラムの[変更]をクリックしPythonを選択すると関連付けされます。Pythonのインストール方法によってはアプリ一覧にPythonが表示されないこともありますが、PCでアプリを選択するからpython.exeを直接指定することで関連付けされます。

pythonコマンド実行時に指定されたソースファイルはトップレベルと呼ばれます。

ファイルの文字コード

Pythonのソースコードは、UTF-8エンコーディングで記述します。

ファイルの改行コード

Pythonソースファイルの改行コードは、LFで統一しておくと、Linux/Windows混在の環境でソースコードリポジトリを介してファイルを共有するときに便利です。

エントリーポイント

Python はスクリプト言語なので、ファイルに書かれた命令を上から順に実行していきます。
モジュールとしてimportされたときもファイルに書かれた命令が実行されます。

スクリプトとして実行されたとき、標準入力から読み込まれたとき、__name__ 変数には main が設定されます。
スクリプトファイルに次の記述を入れておくと、そのファイルがスクリプトとして実行されたときに実行されます。

def main():
    # logic

if __name__ == '__main__':
    main()

他のモジュールからimportされたときは、__name__ には、モジュール名が格納されます。

コマンドライン引数の取得

sysモジュールのargvリストに格納された引数を個々に文字列で取得する方法と、argparseモジュールのArgumentParserを使って引数の取得・解析、ヘルプの表示、説明の表示などを行う方法があります。

Python_コマンドライン引数ライブラリ

以下は標準ライブラリで用意されたsysモジュールとargparseモジュールのコマンドライン解析の概要です。

argv

コマンドラインに羅列された引数をそれぞれ文字列としてリストに格納する、きわめて簡潔なコマンドライン引数ライブラリです。

import sys

args = sys.argv
print(f'引数の個数は{len(args)}')
for arg in args:
    print(f'{arg=})
  • args[0]にはスクリプトファイル名
  • args[1:]で純粋に引数名リスト
argparse

引数の解析を行い、取得できるほか、必須引数、オプション引数、引数名と値、ヘルプの表示などを行う高度なコマンドライン引数ライブラリです。
https://docs.python.org/ja/3/library/argparse.html#module-argparse

import argparse

parser = argparse.ArgumentParser(description="ログを読み込み使用状況をファイルに生成するプログラム")  # ヘルプの説明文を添えてパーサー生成 
parser.add_argument('input')    # 1つ目の必須引数を定義(input は後で引数の値を参照するための識別子となる)
parser.add_argument('output')   # 2つ目の必須引数を定義(output は後で引数の値を参照するための識別子となる)
parser.add_argument('values', nargs='+')  # 3つ目以降複数引数(任意個数)を定義(valuesは後で引数の値を参照する識別子となる。nargsで個数を指定)
parser.add_argument('--line')  # 値を伴うオプション引数を定義(--line NNN と指定、line が後で引数の値を参照するための識別子となる)
parser.add_argument('-w', '--word', action='append')  # オプションを複数指定(配列)(-w alfa -w bravo と指定すると['alfa', 'bravo']とリストで取得)(短縮形の -w charlie と --word charlie との指定が可能)

args = parser.parse_args()      # コマンドライン引数の取り込み
print(f'{args.input=}')         # 1つ目の必須引数を参照
print(f'{args.output=}')        # 2つ目の必須引数を参照
print(f'{args.values=}')        # 3つ目以降の必須引数(複数個)を参照、リストで取得される
print(f'{args.lines=}')         # オプション引数の値を参照

必須引数を指定しないと、ヘルプを表示して終了します。

  • 任意個数の引数 nargs
    nargsに引数の個数を指定します。0個以上:'*', 1個以上:'+', 指定個数はその数を指定します。
    • オプション引数の任意個数指定の場合、action='append'とする方法あり
      -a alfa -a bravo -a charlie とすると、['alfa', 'bravo', 'charlie']とリストになる
  • オプション引数の指定を必須とする required
  • 引数の型を指定する type
    デフォルトは文字列。int, float, ascii, ord, open, argparse.FileType, pathlib.Path, 関数指定も可
    • openは引数で指定されたファイルパスのファイルオブジェクトを返す(open済み)
  • 引数の指定を規定の選択肢から選択する choices
  • 引数の指定がない時の値を指定する default
  • 引数をフラグとして使う action='store_true'

外部設定ファイル

プログラムの動作をカスタマイズ可能にする方法の一つとして、プログラム実行時に設定ファイルを読み込み、その設定に応じた振る舞いをするsettingsライブラリがあります。これは Python 3標準ライブラリです。Pythonプログラムと同じディレクトリに、settings.py の名前で設定ファイルを保管します。settings.py に記述された変数を実行時に読み込み変数の値を使用します。

settingsライブラリ

ユーザーによるファイル指定

スクリプトの実行時に、GUIを構築せず処理対象のファイルをドラッグ&ドロップで指定する方法をいくつか記載します。

コマンドライン引数で指定

スクリプトの実行時に、処理対象ファイルをドラッグ&ドロップでスクリプトのショートカット等に渡してコマンドライン引数でファイルのパスを取得する方法です。

Windows OS

Pythonスクリプトを実行するバッチファイルを作成し、バッチファイルに処理対象ファイルをドラッグ&ドロップします。
拡張子.pyを python.exeに関連付けした場合は、ドラッグ&ドロップを受け付けないことがあります。
assocで関連付けした場合も、同様にドラッグ&ドロップを受け付けないことがあります。

バッチファイルを作成し、コマンドライン引数を python実行コマンドラインに渡します。

python "%~dp0dnd.py" %*
  • %~dp0 は、バッチファイルが存在するディレクトリを指します。
  • %* は、バッチファイルのコマンドライン引数全体を指します。
  • python.exeが環境変数PATHに設定されていない場合は絶対パスでpython.exeを指定します。
    %LOCALAPPDATA%\Programs\Python\python314\python.exe
import sys

files = sys.argv[1:]
for f in files:
    print(f)
macOS

macOSでは、Pythonスクリプトファイルにドラッグ&ドロップして動かすことはできないので、簡便な方法は、ターミナルからPythonスクリプト実行のコマンドを入力し、Enterを押さずにファイルをターミナルにドラッグ&ドロップすることでファイルのフルパスが入ります。

  • ターミナルを開き、python3 コマンドに続けてスクリプトファイル名を入力し、Enterを押さずにおく。
    ~/work$ python3 hello_dnd.py 
    
  • 指定したいファイルをFinder等からターミナルにドラッグ&ドロップする。
    ~/work$ python3 hello_dnd.py /Users/foo/Documents/sample/alfa.txt
    
  • Enterキーを押してスクリプトを実行する

Automatorを使う方法もありますが、定義にpython3(ラインタイム)とスクリプトファイルの絶対パスを指定する必要があるので柔軟性に欠けてしまいます。

標準入力で指定

コマンドライン環境(コンソール)でスクリプトを実行し、input()関数で標準入力待ちしている状態でファイルをコンソールにドラッグ&ドロップすると、そのファイルのパスを取得できます。

    paths = input()
    for path in paths.split():
        print(path)

パッケージ

少し複雑なプログラムになると、複数のファイル(=モジュール)から構成するようになります。
アプリケーションも1つのパッケージとして管理することができます。

__init__.py

project
  +-- myapp
  |     +-- __init__.py
  |     +-- app.py

最初は、空の__init__.pyを用意するだけで構いません。パッケージをインポートすると暗黙的に __init__.py が実行されます。

Python 3.3以降で、__init__.py を置かないディレクトリは名前空間として扱われるようになりました。
ですが、__init__.pyを定義して通常のパッケージとして管理した方が良いでしょう。

__init__.py の応用例
  • パッケージ内のモジュールを簡潔な記述でimportできるよう定義を記述可能
  • パッケージ内グローバルな変数を定義可能
  • パッケージの初期化処理を記述可能
    • 設定ファイルを読み込みパッケージ内グローバル変数を定義
    • ログの初期設定
  • バージョンの定義(__version__
    昨今ではtomlファイルにバージョンを定義、importlib.metadataで参照

プログラムの終了

exit

sys.exit でスクリプトの実行を終了します。引数に指定した値をOSに戻すことができます。

  • sys.exit() リターンコード0でプロセス終了
  • sys.exit(1) リターンコード1でプロセス終了
  • sys.exit('Fatal Error: exit') 標準エラー出力にメッセージを表示し、リターンコード1で終了

構造

クラス

空のクラス

class Alfa:
    pass

passは、classが空であることを指示します。

クラスからオブジェクトを作成するには、an_alfa = Alfa() とクラス名に丸括弧を付与して呼び出します。

クラス属性

class Alfa:
    cell = 'H8'

クラス属性へのアクセスは、クラス名.属性名(Alfa.cell) でも、インスタンス名.属性名(an_alfa.cell)でも可能です。
クラス属性を変更すると、変更後にクラスから生成したインスタンスには変更が反映されます。
変更前にクラスから生成したインスタンスには変更が反映されます。

インスタンス属性

インスタンス属性は、class定義には明記されず、最初にインスタンス名.属性名でアクセスしたときに生成されます。C++/Java系でクラスに慣れているとびっくりする仕様です。
なので、通常はインスタンス属性をクラスの初期化メソッド__init__() で定義します。

class Bravo:
    def __init__(self):
        self.x = 0
        self.y = 0
  • Pythonの属性は公開
  • インスタンス生成後に属性の追加が可能だが、その場合同じクラスの他のインスタンスには属性が追加されない(そのインスタンス固有)

初期化メソッド

class Alfa:
    def __init__(self):
        pass

インスタンス初期化の特殊なメソッド __init__() を定義します。クラスからインスタンス生成時に初期化するメソッドです。
第1引数はselfとします。

メソッド

  • デコレータのないメソッドはインスタンスメソッド
  • @classmethod デコレータがついたメソッドはクラスメソッド
  • @staticmethod デコレータがついたメソッドは静的メソッド
クラスメソッド
class Alfa:
    @classmethod
    def order(cls):
        pass

第1引数はクラスであり、慣用的に cls を使います。

静的メソッド
class Alfa:
    @staticmethod
    def count():
        pass

静的メソッドは、引数に selfcls を取ることはできません。

プロパティ

class Alfa:
    def __init__(self, in_name):
        self.__name = in_name
    @property
    def name(self):
        return self.__name
    @name.setter
    def name(self, in_name):
        self.__name = in_name
  • @propertyデコレータ を付けたメソッドは、a_alfa.name のように属性の参照であるかのように記述して呼び出す
  • @name.setterデコレータを付けたメソッドは、a_alfa.name = 'abc' のように属性への設定であるかのように記述して呼び出す
  • __ を接頭辞に付けた変数(属性)は外部からアクセスできない。

継承

class Bravo(Alfa):
    pass

クラスAlfaを継承したクラスBravoを定義します。

ミックスイン

データクラス

Python 3.7から導入されました。

from datacalsses import dataclass

@dataclass
class Charlie:
    name: str
    age: int = 0
__init__(self, name: str, age: int = 0) メソッドが自動生成されるので、次のように初期化することができます。
  • charlie = Charlie('Angel', 16)
  • charlie = Charlie(name='Angel', age=16)

そのほか、__repr__()__eq__()、などが自動生成されます(dataclassデコレータのオプションで生成の有無を制御可能)。
デフォルト値を指定したフィールドの後ろにデフォルト値を指定しないフィールドを定義するとTypeErrorとなります。
クラス同様メソッドの定義ができます(サンプルでは省略)。

from dataclass import dataclass

@dataclass
class Weather:
    temperature: float
    humidity: float
    id: str = 'NA'

データクラスをイミュータブル(不変)にする場合は、@dataclass(frozen=True) と記述します。

関数

関数の書式

関数は、def文で定義します。defに続き関数名を書き、入力引数を丸括弧に囲んで書き、末尾にコロンを書きます。次のインデントされたコード行が関数の本体となります。

def my_function():
    pass
  • 引数が無しのときは、丸括弧の中が空
  • 戻り値型の指定は関数書式にはなく、本体でreturnを使って値を返す

def文が実行されると関数オブジェクトが生成され、関数名に代入されます。なお、lambda式を用いると名前のない関数オブジェクトを作ることができます。

引数

def my_func(alfa, bravo):
    print(f'{alfa=}, {bravo=}')

引数はカッコの中に引数の変数名を列挙して関数を定義します。

デフォルト値

引数を伴う関数を呼ぶときは、必ず引数を指定するのですが、デフォルト値を引数に持たせると、関数の呼び出し時に引数の指定を省略することができます。

def my_func(alfa, bravo='2')

この場合呼び出し時に my_func(3) と指定すると、bravoにはデフォルト値の2が設定されます。

デフォルト値は省略可能なので、複数の引数をもつ関数を定義するときは、デフォルト値を持つ引数の後にはデフォルト値のない引数を定義することはできません。def my_func(alfa=1, brave): は定義ができません。

複数の引数にデフォルト値を指定した関数を呼び出すときに、任意の引数だけ値を指定して呼び出すときは、名前を付けて引数を指定します。
def my_func(alfa=1, bravo=3, charlie=5) と定義した関数で、bravoにだけ値を指定するときは、my_func(bravo=7) と指定します。

戻り値

複数の戻り値を返す
def multi_values():
    return 404, "not found" 

カンマ区切りの値は、タプルと扱うので、これは (404, "not found")のタプルを1つ返す関数となります。

  • タプルを受け取って各要素にアクセス
ret = multi_values()
print(f'{ret[0]=}, {ret[1]=}')
  • 分解して受け取る
code, message = multi_values()

ローカル変数

仮引数および関数の中で定義した変数はローカル変数となり、関数がスコープとなります。
グローバル変数を関数内で参照することができます。
グローバル変数へ代入する場合、関数内で global 宣言することで可能となります。

a = 3
b = 1

def f():
    l = 12 # ローカル変数
    m = a * 2 # グローバル変数aを参照
    global b
    b = m # グローバル宣言した変数bを変更

ここでいうグローバル変数は、モジュール内スコープの変数です。

モジュール

Pythonでは、Pythonコードを記述したファイルがモジュールとなります。モジュール名は、ファイル名から拡張子.pyを除いた名前となります。(alfa.pyファイルならalfaがモジュール名)

インポート

  • import alfa は、alfa.pyファイルに定義される要素を、alfa.要素で呼び出せるようにする
  • from alfa import bravo は、alfaモジュールの中のbravo要素を、直接bravoで呼び出せるようにする
  • 別名でインポートすることができる
    • import alfa as a は、alfa.pyファイルに定義される要素を、a.要素で呼び出せるようにする
    • from alfa import bravo as phonetic_bravo は、alfa.pyファイルに定義されるbravo要素を、別名phonetic_bravoで呼び出せるようにする
  • モジュールを定義するファイルに書かれている実行文は、最初のインポート時に実行される
インポートの注意点

プログラムコードのファイル名やディレクトリ名が、importする何らかのモジュール名と同じ場合、循環参照エラーとなります。

モジュールのバージョン記述

モジュールにバージョンを指定する場合は、バージョン番号を文字列として保持する__version__ を定義します。

"""モジュールのファイル先頭Docstring""" 
__version__ = "3.1.4" 

import os
  :

モジュールのバージョンを参照するときは、alfa.__version__ と、モジュール名に__version__ を指定します。

パッケージ

モジュール(ファイル)が増えたときに、ディレクトリを階層化してモジュールを配置

指針

クラス、モジュール

  • 同じ振る舞いで異なる内部状態のインスタンスが複数あるときは、クラス
  • 何かを1つだけ用意するときはモジュール(シングルトンとして使える)
  • 複数の値をまとめて捌く(関数の引数に渡すなど)にはクラス
    • タプル、名前付きタプルで賄えるならそれがいい
    • データクラス(Python 3.7以降)
  • 単純な方法を使う
  • 既存の構造を使う。数値、文字列、タプル、リスト、集合、辞書、コレクションライブラリ

型ヒント

Python型ヒントのページを参照

データ

Python のデータ型

基本データ型

名称
bool 真偽値 True, False
int 整数 正負の整数値、大きさの制限はほぼない
float 浮動小数点数 64bit浮動小数点数
complex 複素数
str 文字列
list リスト
tuple タプル
bytes バイト
bytearray バイト配列
set 集合
frozenset 不変集合
dict 辞書
  • 他のプログラミング言語にある配列(固定長で特定の型の連続を添字で指定し読み書き)は基本データ型にはありません。arrayモジュールで配列相当の機能が提供されています。
    リストは可変長で、異なる型を保持することができます。

空のデータ

空のリテラル
str ''""""""""
list []
tuple ()
dict {}
set set()

整数

基数

リテラル
  • 2進数の整数リテラルは、0b1010 のように0bを先頭に記載
  • 8進数の整数リテラルは、0o774 のように0oを先頭に記載
  • 16進数の整数リテラルは、0xA5 のように0xを先頭に記載
文字列表現

整数を、基数を指定して文字列にします。

  • bin(90) => '0x1011010'
  • oct(90) => '0x132'
  • hex(90) => '0x5a'

文字列

クォート

文字列の生成は、シングルクォートまたはダブルクォートで文字を囲みます。
'Alfa' "Bravo"
どちらのクォートを使用しても同じに扱われます。クォートが2種類あることで、たとえば文字列にダブルクォートを含む場合、シングルクォートで文字列を囲むことでエスケープなしに文字列を生成できます。
'He said "I am a Hero."'

コード中で、英語文章を扱う場合はアポストロフィー(シングルクォート文字)がよく登場するのでダブルクォートで文字列を囲むのがよいです。JSONやHTMLなどの文字列を扱う場合は、ダブルクォートがよく登場するのでシングルクォートで文字列を囲むのがよいでしょう。

改行コードは、エスケープシーケンス \n を文字列中に入れます。

複数行文字列

複数行文字列はトリプルクォートを使います。

multiline = """Hello, Alfa.
How are you?
Bye
""" 

ソースコードのインデントに合わせてトリプルクォートを使用した時、各行の先頭にインデントの空白が含まれます。
これを取り除くには、textwrap.dedent(text) を使用します。

r-文字列リテラル

エスケープシーケンスが効かず、そのまま記述した文字のまま扱われます。
"Hello, \nippon"

f-文字列リテラル

f'文字列' とfで始まる文字列リテラル(クォートはシングルでもダブルでも可)は、文字列内で波括弧で囲まれた文字列を式として評価し、結果文字列に置換えます。

name = "Alfa" 
age = 20
print(f'{name} is {age} years old.')

これは、Alfa is 20 years old. と出力されます。

波括弧内で、式文字列の後に=を置くと、式=値と置換されます。

print(f'{name=}')

これは、name='Alfa'と出力されます。

3連引用符にf文字列リテラルを使用することもできます。

print(f'''
Usage {sys.argv[0]} [options]
    -l: long format
    -h: show usage'''
置換フィールドにおける書式指定

0埋め、指数表記、16進数、右寄せ、左寄せ、桁区切りなどの書式指定が可能です。以下例(抜粋)。

書式指定 表示結果 備考
f'{text:8}' hello 8桁表示を指定、左詰めで残りは空白
f'{text:>8}' hello 8桁表示で右詰、文字列を超える桁は空白で埋められる
f'{text:>*8}' ***hello 8桁表示で右詰、*で埋められる
f'{text:^8}' hello 8桁表示で中寄
f'{val:+}' +4126 符号を正負とも指定
f'{val:,}' 4,126 桁区切り
f'{val:08}' 00004126 0埋めありで8桁
f'{val:x}' 101e 16進表記, Xは大文字表記、bは2進、oは8進
f'{pi:.3f}' 3.142 小数点以下3桁に丸めた固定小数点表記
f'{pi:e}' 3.141593e+00 科学的表記
f'{dt:%Y/%m/%d}' 2026/01/25 datetimeオブジェクトの書式指定
[:][.][^][-][ ][ ][ ]
 |  |  |  |  |  |  +- 変換型
 |  |  |  |  |  +---- 文字数の上限・精度
 |  |  |  |  +------- 幅の下限
 |  |  |  +---------- 負号
 |  |  +------------- 配置(< 左寄せ、> 右寄せ、^ 中央揃え)
 |  +---------------- パディング文字
 +------------------- コロン

b-文字列リテラル

b'文字列' とbで始まる文字列は、bytesリテラルでバイト配列の文字列表現を記述します。文字列にはASCII文字またはASCIIコードのエスケープ表現のみが許容されます。

james = b'\x30\x30\x37'

jamesは、bytes型で3つの要素 0x30, 0x30, 0x37 を保持します。

正規表現

import re で正規表現モジュールをインポートします。

使い方
import re
  :
my_pattern = re.compile(r'^(\d+)\s+(\w+).*$')
  :
data = '1324   ALFA_OMEGA comments'
matched = my_pattern.match(data)
if matched:
    p1 = matched.group(1)
    p2 = matched.group(2)

正規表現文字列は、r文字列で指定すると、バックスラッシュが特別扱いされないので、正規表現のバックスラッシュを文字列中で2重にしなくていいのが便利です。

使い方(compileなし)
import re

data = '2024-01-20'
matched = re.match(r'\d{4}-\d{2}-\d{2}', data)
記法メモ
  • 非貪欲(non-greedy)なマッチ: *?, +?, ??
  • メタ文字 .^$*+?{[¥|()
  • 特殊シーケンス
    • \d 数字1文字とマッチ [0-9]
    • \D 数字以外の1文字とマッチ [^0-9]&
    • \s あらゆる空白文字とマッチ [ \t\n\r\f\v]
    • \S 空白以外のあらゆる文字とマッチ
    • \w 英数字とマッチ [a-zA-Z0-9_]
    • \W 英数字以外とマッチ
fullmatch

正規表現パターンが文字列全体と一致するかどうかを判定します。

数値と文字列の変換

  • 文字列からint
    int('13579')
  • 文字列からfloat
    float('246.8')

文字列処理あれこれ

s1="Hello,"
s2="World"

  • 文字列同士の連結 s1+s2 > "Hello,World"
  • 反復 s2*3 > "Hello,Hello,Hello"
  • 文字数 len(s1) > 6
    ユニコード文字数となります。
  • 文字列を1文字ずつイテレート for c in s3:
  • 文字列を配列添字(インデックス)でアクセス s2[3] > l
    スライスも使用可能 s1[2:4] > "ll"
  • 置換 s2.replace("ld", "k!")
  • 先頭一致 s1.startswith("H")
  • 末尾一致 s1.endswith(",")
  • 空文字かの判定 if not s1:
  • 大文字に変換 s1.upper() > "HELLO,"
  • 小文字に変換 s2.lower() > "world"
  • 先頭1文字を大文字、他を小文字に変換 s3.capitalize()
指定の文字列を含んでいるか
  • 含んでいる場合にTrue
    if "alfa" in text:
  • 含んでいない場合にTrue
    if "alfa" not in text:
文字列を指定の区切り文字で分割(split)
  • デフォルトの区切り文字(スペース、タブ、改行)で文字列を分割しリストを返却
    words = text.split()
  • 区切り文字をしてして分割
    words = text.split(',')
リストを区切り文字で結合(join)

",".join([s1, s2])

文字列を改行で分割(splitlines)

改行コードはOSによって異なるので、改行で分割する場合は、splitlinesを使うと便利です。

  • Windows: \r\n
  • Linux: \n
文字列の前後の空白除去(strip)
  • s5.strip() 空白を両端から取り除く
  • s5.lstrip() 空白を左端から取り除く
  • s5.rstrip() 空白を右端から取り除く

指定文字を取り除く操作も可能
s1.strip(",") カンマを両端から取り除く

タプル

p1 = 3.1, 2.4
p2 = 1.2, 1.8

p1 == p2 # False
p1 > p2  # True
p1 < p2  # False

x1, y1 = p1  # x1=3.1 x2=2.4
print(f'{p1[0]=}, {p2[0]=}')  # p1[0]=3.1, p1[1]=2.4

名前付きタプル

from collections import namedtuple

Point = namedtuple('Point', ('x', 'y'))
:
p1 = Point(3.1, 2.4)
print(f'{p1.x=},{p1.y=}')

辞書

キーと値の組み合わせを複数保持するデータ型です。

datum = { 'TIME': time, 'USER': user, 'VIRT': vert, 'RES': res }
print(f"{datum['TIME']} {datum['VIRT']} {datum['RES']}"}

また、次の記述も可能です。

datum = dict(TIME=time, USER=user, VIRT=vert, RES=res)
print(f"{datum['TIME']} {datum['VIRT']} {datum['RES']}"}

キーワード引数名(上述では、TIME, USER, VIRT, RES)は文字列型のキーとなります。そのため、引数名は英字で始まり英数字とアンダースコアのみ使用できます。

要素へのアクセス

  • キーに値をセット。キーが存在すればその値を変更し、キーが存在しなければ新たなキーと値としてセットします。
    datum['TIME'] = datetime.time(2,4,6)
  • キーの値を取得(1)。キーが存在しないと例外 KeyError が発生します。
    t = datum['TIME']
  • キーの値を取得(2)。キーが存在しないとNoneが取得
    t = datum.get('TIME')
  • キーが存在することを確認してからキーの値を取得
    if 'TIME'  in datum:
        t = datum['TIME']
    
  • イテレート
    for k,v in datum.iteritems():
        print(k, v)
    
  • 全てのキーを取得
    datum.keys()
  • 全ての値を取得
    datum.values()
  • キーと値のペアをタプルのリストで取得
    datum.items()

値からキーを逆引き

リスト内包表記を使って、キーと値を取り出し値と一致した要素のキーを取得します。

  • 実装1)値に対応するキーを取得、同じ値が複数のキーに登録されているときは、キーのリストを取得
def keys_by_value(dic, value):
    return [k for k, v in dic.items() if v == value]
  • 実装2)値が重複しないことを前提に値に対応するキーを取得
def key_by_value(dic, value):
    keys = [k for k, v in dic.items() if v == value]
    if keys:
        return key[0]
    return None

要素を削除

del datum['TIME']

辞書内包表記

リスト内包表記のように、辞書型にも内包表記があります。

d = { s: len(s) for s in names }

条件をつけた内包表記も可能です。

@d = { k: v for k, v in zip(keys, values) if v % 2 == 1 }@t

リスト

順序が保証された値のリストを持つデータ型です。
my_list = [1, 3, 5, 7, 11, 13]

  • 要素数:len(my_list)
  • インデックスアクセス:my_list[3] -> 7、インデックスは0から始まる
  • スライス:my_list[2:4] -> [5, 7, 11]、インデックスが2から4の前までを取り出す
    • 最後の要素 my_list[-1:] -> [13](要素1つのリスト)、my_list[-1] -> 13 要素
    • マイナスのインデックスは末尾からのアクセスになる。最後から2番目の要素 my_list[-2] -> 11
  • max(my_list) -> 13
  • min(my_list) -> 1
  • my_list * 2 -> [2, 6, 10, 14, 22, 26]
  • 要素の実在:11 in my_list -> True
  • 要素を末尾に追加:my_list.append(17)
  • リストを末尾に追加:my_list.extend([17, 19]) -> [1, 3, 5, 7, 11, 13, 17, 19]
  • 要素を先頭に追加:my_list.insert(0, 999) -> [999, 1, 3, 5, 7, 11, 13, 17, 19]
    • insertは第1引数で挿入先のインデックスを指定するので、0で先頭、その他の値で任意の位置に要素を挿入
  • リストの要素数 len(my_list)
  • リストの要素の出現回数 my_list.count(5)
  • リストの要素の削除
    • 全削除 my_list.clear()
    • 指定したインデックスの要素を削除 my_list.pop(3)
    • 指定した要素を検索し最初に見つけた要素を削除 my_list.remove(11)
  • sort, reverse, copy
  • 空リストの判定 if not mylist:

多次元リスト

my_multi_list = [[1,3], [5,7], [11,13,17]]

  • my_multi_list[1] -> [5,7]
  • my_multi_list[1][1] -> 7

入れ子のリストを平坦化

my_list = [[1,3,5], 7, [11, 13]] 不規則な入れ子リスト

  • 問題点) リストの要素にリストや非リストが混在する場合
    • itertools.chain やリスト内包表記では平坦化できません

次のように再起的に平坦化する関数を定義します。

def flattern(l):
    for el in l:
        if isinstanceof(el, collections.abc.Iterable) and not isinstanceof(el, (str, bytes)):
            yield from flatten(el)
        else:
            yield el
  • 出典)https://note.nkmk.me/python-list-flatten/

リスト内包表記

for/inによる反復処理の結果をリストに生成する記述方法です。

書式1: [ 式 for <item> in <iterable> ]
書式2: [ 式 for <item> in <iterable> if 条件式 ]

  • 例1 range関数で出力したデータ群をリストにする
    [n for n in range(1, 7)] -> [1,2,3,4,5,6]
    [n-1 for n in range(1, 7)] -> [0,1,2,3,4,5]
  • 例2 range関数で出力したデータ群のうち奇数のデータをリストにする
    [n for n in range(1,7) if n % 2 == 1] -> [1,3,5]
  • 例3 文字列リストからキーワードリストすべてを含むものをリストにする
    [p for p in plist if all(kw in p for kw in kwlist)]

リストの要素 k と k+1 との差分のリスト

例えば、[2, 3, 5, 7, 11, 13, 17] のリストAに対して、要素と次の要素との差のリスト [1, 2, 2, 4, 2, 4]を生成したいとします。
まず、対象リストAから、先頭を除くリストBを生成します。[3, 5, 7, 11, 13, 17]

zip関数で、最初のリストAと、リストAから先頭を除いたリストBの2つのリストの要素を先頭から順番に取り出します。

primes = [2, 3, 5, 7, 11, 13, 17]
diffs = [i-j for i,j in zip(primes, primes[1:])]
  • zip関数に渡す2つのリストの要素数が異なるときは、多い分が無視されます。
  • 2つのリストを先頭から要素をそれぞれ取り出し、要素の差分を計算して新しいリストを生成していきます。

スライス

  • [:] 先頭から末尾までのシーケンス全体
  • [start:] startオフセットから末尾まで
  • [:end] 先頭から end-1オフセットまで
  • [start:end:step] step個毎にstartオフセットからend-1オフセットまで
    • オフセットの数値指定を負の値にすると末尾からのオフセットとなる

集合

順序のない重複排除した値の集合を保持するsetです。
my_set = {'Hello', 'Python', 'World'}

集合演算ができます。細部は次のWikiページに記載します。
Python_集合(set)

日時型

参考:Pythonで日時を扱う

datetime

標準のdatetimeモジュールがあります。

  • datetime.datetime 日付と時刻
  • datetime.date 日付
  • datetime.time 時刻
  • datetime.timedelta 時間(時刻差)
コンストラクタから生成
import datetime

dt1 = datetime.datetime.now()  # 今の日時をローカルタイムで取得
dt2 = datetime.datetime(2023, 1, 15, 12, 30, 0)  # 2023年1月15日12時30分のローカルタイムを生成
dt3 = datetime.datetime(2023, 1, 15, 3, 30, 0, tzinfo=datetime.timezone.utc)  # 2023年1月15日3時30分のUTC日時を生成
文字列から生成
import datetime

dt1 = datetime.datetime.strptime("2023-02-10 01:23:45", "%Y-%m-%d %H:%M:%S")
t1 = datetime.datetime.strptime("01:23:45", "%X").time()
  • strptime関数は、datetimeクラスおよびdateクラスのクラスメソッドで、文字列を指定したパターンで解析してdatetimeオブジェクトを生成します。
    残念ながら、timeクラスにはstrptimeメソッドが用意されていないので、datetimeで文字列をパースしてから、timeメソッドでtimeオブジェクトに変換します。

array型

配列相当の機能がarrayモジュールのarray型で提供されています。格納可能な値の型を指定して生成し、その型の値のみ格納可能です。1次元配列のみで、要素数は可変長です。
ファイルとの入出力は用意されてますが、他のライブラリでサポートされるものはほぼなく、数学関数などでベクトル量を扱うならNumPyを使うのが良い解です。

演算子

演算子一覧

  • 四則演算子 + - * /
    • 剰余 %
    • 除算(切り捨て) //
    • 冪乗 **
  • 代入演算子 += -= *= /=
  • 比較演算子
    • 等しい == is
    • 等しくない != is not
    • 小なり <
    • 大なり >
    • 以下 <=
    • 以上 >=
    • 含む in
    • 含まない not in
  • 論理演算子
    • 論理積 and
    • 論理和 or
    • 否定 not
  • ビット演算子
    • 反転 ~
    • AND &
    • OR |
    • XOR ^
    • 左シフト <<
    • 右シフト >>

三項演算子

Conditional Expressions なので演算子とはことなりますが、文ではないので演算子のひとつとして記載します。

例)

result = "even" if a % 2 == 0 else "odd" 
         ^^^^^^    ^^^^^^^^^^      ^^^^^
         真の時の値  条件式          偽の時の値

まず真の時の値(評価結果が値となる式も可)を記述し、続いて if <条件式> を記述、その後に else で偽の時の値を記述します。
条件式が真の時の値の後に置かれるので一瞬分かりにくいかもしれません。

制御

繰り返し制御

for

for ターゲット in イテレータオブジェクト:
    処理
else:
    処理

Pythonでは、for文、while文にもelse節が用意されています。else節は、for節の最後の繰り返し処理が実行されたあとに実行されます。breakで繰り返しの途中でfor節を抜けた時はelse節は実行されません。また、break以外でもreturnや例外の発生でループの途中でfor節を抜けた場合もelse節は実行されません。

else節の使用例として、for文の繰り返し処理を正常時にbreakやreturnで抜けるように記述し、もし途中で抜けずに最後の繰り返しが終了した場合は異常としてelse節で異常対応コードを記述するということができます。

典型的には、リストから要素を順次取り出しループ処理をします。

numbers = [1, 3, 5, 7, 11, 13]
for n in numbers:
    print(n)

インデックスを参照したいときは、

numbers = [1, 3, 5, 7, 11, 13]
for i, n in enumerate(numbers):
    print(f'({i=}, {n=}')

とイテレータをenumerate()で包み、インデックスとイテレータの要素を順次取り出します。

要素を列挙したくない時や固定回数を繰り返し処理したい時は、range関数などで範囲指定することができます。

for n in range(5):
    print(n)
  • range(5) は、0から5の整数を生成
  • range(3, 6) は、3から5までの整数を生成
  • range(0, 10, 2)は、開始値に0、終了値(含まない)に10、増分に2を指定、0,2,4,6,8の整数を生成

while

while 条件式:
    処理
else:
    処理
  • while節の条件式が成立しなかったときに else節が実行される
  • while節の中でbreak文を実行すると、while節を抜けるがこのときelse節は実行されない
  • while節の中でcontinue文を実行すると、while節の先頭(条件式)からループを開始する

分岐

if

if 条件式:
    処理
elif 条件式:
    処理
else:
    処理

elifは必要に応じて記述でき、複数記述可能です。
elseは必要に応じて記述できます。最後に1つ記述します。

パターンマッチ(match-case)

Python 3.10以降で導入された文法です。

match value:
    case 1:
        print('One')
    case 2:
        print('Twe')
    case _:
        print('Many')
  • caseには、ガード条件(case 3 if flag)でifを指定することができます。case x if x > 3のような指定も可能です。
  • caseには、複数の値(case 3 | 4 | 5:)を指定することができます。複数の条件は、この例のようにパイプ区切りの他、リストで指定することができます。

例外

エラーの通知方法

例外を使わないエラー通知

関数の戻り値で正常終了かエラー終了かを戻り値で通知します。

  • (あまり良くない方法)正常終了時は関数の値を返し、エラー終了時はNoneを返す
  • タプルで、正常・異常の識別と、正常時の関数の値を返す

エラーの握りつぶしが発生しやすいのがデメリットです。
関数を呼び出した側で、正常・異常のチェックをしないと、エラーに気づかず処理が進んで値(None)を参照するところでプログラムが異常発生で停止し、原因が分かりづらいといった状況が起きます。

例外を使うエラー通知

raise文で例外を発生させます。関数呼び出し側で try構文でエラーをハンドリングします。ハンドリングしない場合、ランタイムが例外で停止します。

例外の使い方

例外は、BaseExceptionから派生したクラスのインスタンスです。ユーザー定義例外は、Exceptionから派生します。

標準例外

組み込み例外のクラス階層を 表示

例外の補足

try:
    例外がスロー去れるかもしれない処理
except FileNotFoundError:
    ファイルがない時のエラー処理
except ValueError as err:
    値のエラー処理、errで発生した例外にアクセスする
except:
    上述の例外以外がスローされた時の処理
else:
    例外がスローされなかった時に行う処理
finally:
  例外の発生有無によらず最後に実行する処理

独自例外の定義

class MyApplicationException(Exception):
    pass

独自例外の定義は、Exception(またはその派生クラス)を派生します。

for data in list:
    if not data.isValid():
        raise MyApplicationException('data is not valid')

入出力

コンソールの入出力

print関数

引数に指定した文字列を標準出力に出力し改行します。

改行の抑制

改行を抑制するには、print('Hello,', end='') とend引数に空文字列を指定します。デフォルトはend='\n'なので改行します。
end=','とするとカンマ区切りとなります。

文字の色付けをして表示

エスケープシーケンスで色指定が可能です。
print('\033[31m' + 'Hello, Red' + '\033[0m')

[31m の31が赤を指定します。他の値として次を指定可能です。
30:黒、31:赤、32:緑、33:黄、34:青、35:紫、36:水色、37:白

文字の背景色付けをして表示

T.B.D.

input関数

引数に指定したメッセージを表示し、コンソールからユーザーの文字入力を受け付けます。

name = input("Your name?> ")

コンソールに Your name?> と表示し、ユーザーのキー入力を受け付けます。Enterキーを押すとそれまでの入力文字が戻り値として返ります。

ファイルの入出力

詳細は、Python_ファイル入出力ライブラリページ参照。

ファイルのパス指定

OS固有のパス指定
  • Linux/MacOS
    '/home/foo/work/data.txt'
    '/Users/foo/Documents/data.txt'
  • Windows
    'C:\\Users\\foo\\Documents\\data.txt'
    r'C:\Users\foo\Documents\data.txt'
    Windowsはパスセパレータがバックスラッシュなので、文字列中でエスケープ文字となり、2重に重ねて指定するか、raw文字列で指定します。
OS非依存のパス指定

pathlib ライブラリ(Python 3.4以降)を使うと、文字列でパスセパレータを指定しないのでOS固有のパスセパレータ使用を回避でき、OSポータブルな記述が可能です。

from pathlib import Path

data_file = Path('Documents') / 'work' / 'data.txt'

Pathは、openに渡すことができます(Python 3.6以降)。

パスからディレクトリ・ファイル名・拡張子の切り出し

os.pathパッケージを使用した場合

import os
  :
path = 'C:\\Users\\torutk\\works\\alfa.bin'
os.path.basename(path) => 'alfa.bin'
os.path.dirname(path) => 'C:\\Users\\torutk\\works'
os.path.splitext(path) => ('C:\\Users\\torutk\\works\\alfa', '.py') 

pathlibパッケージを使用した場合

from pathlib import Path
  :
path = Path('C:\\Users\\torutk\\works\\alfa.bin')
path.name => alfa.bin
path.stem => alfa
path.suffix => bin
path.parent => C:/Users/torutk/works
path.parents[0] => C:/Users/torutk/works
path.parents[1] => C:/Users/torutk
path.parents[2] => C:/Users
path.parents[3] => C:/

ファイル・ディレクトリの取得

指定したディレクトリの直下にあるファイルおよびディレクトリを取得します。

  • os.listdir関数を使う方法(古い方法)
  • pathlibパッケージを使う方法(新しい方法)

おすすめはpathlibなので、こちらを調べます。

pathlibパッケージを使う
from pathlib import Path

p = Path('/mnt/data/alfa')
items = p.glob("*")    # Pathの直下にあるファイルおよびディレクトリをリスト化
  • p.glob("*") は、パス(ディレクトリ)の直下にあるワイルドカードに合致するファイルまたはディレクトリを取得
    ワイルドカードに、"**/*" と指定するとサブディレクトリを検索対象としますが、次のrglobを指定した方がわかりやすいです。
  • p.rglob("*") は、パス(ディレクトリ)の下を再帰的に検索してワイルドカードに合致するファイルまたはディレクトリを取得

glob()、rglob()の戻り値はイテレータ(ジェネレータ)なので、forなどでイテレートするかlistに変換します。

for f in items:
    print(f)

次のようにプリントされます。

/mnt/data/alfa/readme.md
/mnt/data/alfa/config.dat
/mnt/data/alfa/old
ファイルのみを表示したい
from pathlib import Path

p = Path('/mnt/data/alfa')
items = [p for p in p.glob("*") if p.is_file()]    # Pathの直下にあるファイルをリスト化
print(items)

ここでは。リストの内包表記を使っています。イテラブルなオブジェクトに対して、条件式がTrueのもののみを変数に順次入れ、式で評価した値をリストに詰めていきます。

[ 式 for 変数 in イテラブル if 条件式 ]

ファイル名だけをprintしたいときは、
items = [p.name for p in p.glob("*") if p.is_file()]

パスの検査

項目 os.path pathlib
ディレクトリまたはファイルの存在 os.path.exists(p) p.exists()
ファイルの存在 os.path.isfile(p) p.is_file()
ディレクトリの存在 os.path.isdir(p) p.is_dir()

パスの操作

pathlibを使ったパスの操作について

ディレクトリ作成

既存のディレクトリの下に新しいディレクトリを作成する場合

p = Path("data/backup")
p.mkdir()

dataディレクトリが存在しないとエラーになります。その場合、p.mkdir(parents=True) と指定します。

ディレクトリの削除

空のディレクトリを削除します。

p = Path("data/backup")
p.rmdir()

空でないディレクトリを一括削除する場合

import shutil

p = Path("data/backup")
shutil.rmtree(p)
ファイル名の変更
  • 拡張子を変更 p.withsuffix(".bak")
  • ファイル名を変更 p.with_name("mydata.bak")

ファイルの読み込み(行単位のテキストファイル)

注)open関数でファイルを開いた時は、ファイルの処理が終わったらclose関数でファイルを閉じる必要があります。
with構文を使用すると最後にcloseが呼ばれます。

行単位に読み込み

open()関数でファイルをオープンし、イテレータで1行ずつ読み込みます。

with open('input.txt', 'r') as f:
    for line in f:
        print line
全ての行を読み込み
with open('input.txt', 'r') as f;
    lines = f.readlines()
for文でopen

for l in open('input.txt', 'r'): のようにファイルをopenしてすぐfor文でイテレートする書き方を見かけます。
with文と同様、for文を抜けると自動的にcloseされますが、リソースの自動的なクローズはwith文に統一した方が一貫性が得られます。

ファイルのopenモード

主モード

  • r 読み出し
  • w 書き込み
  • a 追記

副モード

  • + 更新
  • b バイナリ

CSVファイル

import csv

reader = csv.reader(file('input.csv', 'r'))
for row in reader:
    print(row[0])
  • 読み込んだデータはすべて文字列となるので数値として扱うには、int(row1)などのように変換が必要

ロギング

標準の logging モジュールを使用してロギングを行います。
Logger、 ログレベル、ハンドラー、フォーマッターなどの機能が提供されています。

ロギング概要

Loggerには、デフォルトのルートロガーと、アプリケーションやライブラリで固有に設けるロガーがあります。
ロガーはレベルに対応したメソッド(debug, info, warning, error, critical)が提供しているので、これらのメソッドに文字列を渡してログ出力します。

デフォルトのロガーを用いる例を次に示します。

import logging

logging.debug('Hi DEBUG!')
logging.info('Hi INFO!')
logging.warning('Hi WARNING!')
logging.error('Hi ERROR!')
logging.critical('Hello CRITICAL!')

デフォルトでは、ルートロガーとハンドラーそれぞれWARNINGレベル以上のログレベルのメッセージのみ出力されます。ルートロガーの設定をいじることは可能ですが(logging.basicConfig)、前述の通りアプリケーションやライブラリで専用のロガーを作成してそれを設定します。

ロガーの作成

名前を付けてロガーを作成、ロガーに出力レベルと出力先を設定します。

import logging

logger = logging.getLogger(__name__)  # 明示的にロガー名を指定するか、__name__でモジュール名を設定
logger.setLevel(logging.INFO)  # ログの出力をINFOレベル以上にする
logger.addHandler(logging.StreamHandler())  # ログの出力先(Handler)を標準エラー出力に
  • addHandlerで標準エラー出力を指定しています。指定しない場合、ルートロガーのHandlerを継承して使用しますが、ルートロガーの設定を引きずってしまいます。
  • コンソールとファイルと両方にログを出したい場合は、StreamHandlerとFileHandlerを生成し、それぞれをロガーにaddHanlderします。
  • ログレベルのフィルターはロガーだけでなく、それぞれのHanlderにも設定可能です。
標準エラー出力にフォーマットを指定して出力する独自ロガーを作成
    import logging

    logger = logging.getLogger(__name__)
    logger.setLevel(logging.DEBUG)
    handler = logging.StreamHandler()
    formatter = logging.Formatter('%(asctime)s %(levelname)s %(funcName)s - %(message)s')
    handler.setFormatter(formatter)
    logger.addHandler(handler)

出力メッセージ例

2023-06-04 17:22:14,072 INFO main - Processing 1440 messages
  • フォーマッターの指定
    • %(asctime)s は、そのメッセージのログを生成した時刻
    • %(levelname)s は、そのメッセージのログレベル名
    • %(funcName)s は、そのログが要求された関数名
    • %(message)s は、ログのメッセージ文字列

クリップボードの入出力

TkInterを使ったクリップボード

Python標準搭載のTkInter ライブラリを使ってクリップボードとテキストの入出力を行います。
GUIを開かなくてもコマンドラインツールからクリップボードへのアクセスが可能です。

クリップボードの内容を取得
import tkinter

tk = tinter.Tk()
tk.state("iconic")  # 1)
try:                # 2)
    clip_text = tk.clipboard_get()
    lines = clip_text.splitlines()
except:
    lines = ''

for line in lines:
    print(line)
  • 1)tkの初期化でトップレベルウィンドウが生成・表示されるので邪魔な場合は最小化します
  • 2)クリップボードが空の時などで例外が発生することがあるので、clipboard_getはtry文とともに実行します。

ライブラリ

標準ライブラリ

数学関数

mathモジュールとして、各種数学関数が提供されています。

外部コマンド

Pythonから別なコマンドを実行する方法はいくつかありますが、推奨はsubprocessライブラリです。

スタイル

命名規約(PEP 8)

Pythonコードの標準ライブラリで採用されているスタイルガイド PEP8 があります。

PEP8 日本語訳

ファイル

  • ソースコードのファイルはUTF-8を使用する

スタイルに関する規約

インデント、行の長さ、行間の空行などに関する規約

  • 1レベルインデントはスペース4つ
  • インデントにはタブは使わずスペースを使う
  • 1行の長さは最大79文字まで
    docstringやコメントは72文字まで
  • 長い式が複数行に渡る場合、4スペース分インデントする
  • トップレベルの関数やクラスは2行ずつ空ける
  • クラス内部ではメソッドは1行ずつ空ける
  • 辞書ではキーとコロンの間に空白を入れない。値の前にスペースを1つ入れる
  • 変数の代入の=演算子の前後にはスペース1ついれる
  • 型アノテーションでは変数名とコロンの間に空白を入れない、型情報の前にスペースを1つ入れる

importの順番

Python標準、サードパーティ、自作の順で

命名

識別子の種類 命名ルール
モジュール名 全て小文字の短い名前、アンダースコアを交えてよい
パッケージ名 全て小文字の短い名前、アンダースコアは使わない
クラス名 (パスカルケース)
関数名 小文字のみ、アンダースコアを交えてよい
変数名
メソッド名
インスタンス変数名
インスタンスメソッドのはじめの引数名 self
クラスメソッドのはじめの引数名 cls
定数名 大文字で単語をアンダースコアで区切る

Docstring(ドキュメント)

ソースコード中に、モジュールや関数の仕様や使い方を記述するDocstringの書き方をまとめます。

Pythonでは、主に次の3つのDocstringのスタイルがあります。

  • reStructuredText スタイル
    Python公式スタイルですが、記述行が多く、他のスタイルに比べると可読性に若干劣ります。
  • Google スタイル
    Googleのスタイルガイドです。
  • Numpy スタイル
    ライブラリ Numpyで採用されているスタイルです。

Docstringは、モジュール(ファイル)、関数、クラスについて記載します。3連のダブルクォートで文字列として記述します。

  • 1行で簡潔に書く場合
    """簡潔な1行説明""" 
    
  • 複数行で記述する場合
    """概要を1行目で説明
    
    概要の後に1行開けてから詳しい説明を複数行に渡って記載する。
    """ 
    

Google スタイルのDocstyle

モジュール(ファイル)のDocstring
"""1行でこのモジュール/プログラムの概要を記述.

1行の空行を入れて、このモジュール/プログラムの全体的な説明を記述。
補足として、公開するインタフェース、実行例を書いても良い。
""" 
クラスのDoctring
class Greeter:
    """挨拶を司る

    詳しい説明があれば、概要の後に空行を入れて説明を記載する。

    Attributes:
        name (string): 挨拶主の名前
        message (string): 挨拶文
        count (int): 挨拶を実施した回数
    """ 
    def __init__(self, name, message):
        """インスタンスの初期化""" 
        self.name = name
        self.message = message
        self.count = 0

    def greet(self):
        """標準出力に挨拶メッセージ""" 
        print(f'I am {self.name}, {self.message}')
        self.count += 1

  • init の引数は、上述のようにクラスのdocstringに記述することができる
  • クラスの属性は Attributes: に記載
関数のDoctoring
def sum(a, b):
    """2つの整数値を加算する

    詳しい説明があれば、概要の後に空行を入れて説明を記載する。

    Args:
        a (int): 被加数の値
        b (int): 加数の値

    Returns:
        int: 加算結果

    Raises:
        XxError: 加算時にXxエラー
    """ 
  • 引数(Args:)には、関数が受け取る引数の説明を、引数名 (型名): 説明 の書式で記載
  • 戻り値(Returns:)には、関数が返却する値の説明を、型名: 説明 の初期で記載
  • 引数(Args:)、戻り値(Returns:)以外にも、使用例(Examples:)、例外(Raises:)、TODO:、などが記載可能
関数のDocstring(型ヒント使用時)
def sum(a: int, b: int) -> int:
    """2つの整数値を加算する

    詳しい説明があれば、概要の後に空行を入れて説明を記載する。

    Args:
        a: 被加数の値
        b: 加数の値

    Returns:
        加算結果

    Raises:
        XxError: 加算時にXxエラー
    """ 
  • 型アノテーションで関数の引数および戻り値の型を記述しているので、Docstringコメントにおける引数・戻り値の型名は省略する

参考文献

書籍

  1. Introduction Python SECOND EDITION, Bill Lubanovic, O'REILLY, 2021
    邦訳「入門 Python 3 第2版、鈴木駿 監訳、オライリージャパン、2021」
  2. Effective Python 125 SPECIFIC WAYS TO WRITE BETTER PYTHON Third Edition, Brett Slatkin, Pearson Education 2025
    邦訳「Effective Python Pythonプログラムを改良する125項目、鈴木駿 訳、オライリージャパン、2025」

インターネット

  1. Python 3.12 ドキュメント
    https://docs.python.org/ja/3.12/
  2. Python コードのスタイルガイド(PEP8)
    https://pep8-ja.readthedocs.io/ja/latest/


10日前に更新