プロジェクト

全般

プロフィール

操作

第13章 特定のデータフォーマットを扱う

CSV ファイルを扱う csv

CSV, TSV フォーマットのファイルの読み取り、書き込みを行う機能

  • CSV ファイルの読み込みと書き込み

    関数名 解説 戻り値
    reader(csvfile, dialect='excel', **fmtparams) CSV ファイルの各行を反復処理するような reader オブジェクトを返す reader オブジェクト
    writer(csvfile, dialect='excel', **fmtparams) CSV ファイルのデータを指定方法で書き込むための writer オブジェクトを返す writer オブジェクト
    • csvfile には、イテレータープロトコルをサポートするオブジェクトを指定

    • dialect には、以下の 書式化パラメーターセット 、または Dialect サブクラスのインスタンスを指定できる

      • excel Excel で出力される CSV ファイル

      • excel-tab Excel で出力される TSV ファイル

      • unix 終端記号を \n とするファイル


        書式化パラメーターセットによる、各書式化パラメーターのデフォルト値

        パラメーター
        セット
        delimiter quatechar skipinitialspace lineterminator
        excel , " False \r\n
        excel-tab \t " False \r\n
        unix , " False \n


        Dialect クラスの主な属性

        属性 デフォルト 解説
        delimiter , 区切り文字 (1文字からなる文字列)
        quotechar " 引用符文字
        skipinitialspace False Trueの場合、delimiter の直後に続く空白は無視される
        lineterminator \r\n writer が使用する、各行の終わりを表す文字列
    • reader オブジェクトで CSV 読み込み

      "id","都道府県","人口(人)","面積(km2)"
      "1","東京都","13900000","2194.05"
      "2","神奈川県","9200000","2416.10"
      "3","千葉県","6200000","5157.50"
      "4","埼玉県","7300000","3797.75"
      
      >>> import csv
      >>> with open("01_sample.csv", mode="r", encoding="utf-8") as f:
      ...     reader = csv.reader(f)
      ...     for row in reader:
      ...         print(row)
      ...
      ['id', '都道府県', '人口(人)', '面積(km2)']
      ['1', '東京都', '13900000', '2194.05']
      ['2', '神奈川県', '9200000', '2416.10']
      ['3', '千葉県', '6200000', '5157.50']
      ['4', '埼玉県', '7300000', '3797.75']
      
      >>> dialect = reader.dialect
      >>> dialect.quotechar
      '"'
      >>> dialect.lineterminator
      '\r\n'
      >>> dialect.doublequote
      True
      >>> dialect.skipinitialspace
      False
      >>> dialect.delimiter
      ','
      
    • writer オブジェクトで CSV 書き込み

      メソッド名 解説
      writerow(row) データを書式化し、writer のファイルオブジェクトへ書き込む
      row には文字列か数値のイテラブルを指定
      writerows(rows) 複数行を書き込む
      rows には writerow() の row と同様のオブジェクトのイテラブルを指定
      >>> with open("writetest.tsv", mode="w", encoding="utf-8") as f:
      ...     writer = csv.writer(f, dialect="excel-tab")
      ...     for i in range(5):
      ...         writer.writerow([i, "x", i, "=", i**2])
      ...
      11
      11
      11
      11
      12
      
      0	x	0	=	0
      1	x	1	=	1
      2	x	2	=	4
      3	x	3	=	9
      4	x	4	=	16
      
    • 辞書データを用いた CSV ファイルの読み込みと書き込み

      • class DictReader(f, fieldnames=None, restkey=None, restval=None, dialect='excel', *args, **kwargs)

        • f イテレータープロトコルをサポートするオブジェクト
        • fieldnames 辞書のキーをシーケンスで指定 (未指定の場合は f の最初の行の値が使用される)
        • restkey restval 実際に読み込んだデータが、フィールド数 (fieldnames または f の1行目) と不一致である場合に使用される値
          • 実データのフィールド数が多い場合、残りの列の値はリストとしてまとめられて restkey キーの値となる
          • 実データのフィールド数が少ない場合、足りない値は restval によって埋められる
        • dialect (略)
        • 戻り値 DictReader オブジェクト
      • class DictWriter(f, fieldnames, restval='', extrasaction='raise', dialect='excel', *args, **kwargs)

        • f (略)
        • fieldnames 書き込み時に渡される辞書の値をどの順でファイルへ書き出すかをシーケンスで指定
        • restval fieldnames に指定のキーが書き込みデータに存在しない場合に値として使用する文字列を指定
        • extrasaction fieldnames に存在しないキーが書き込みデータに存在する場合の動作
          • raise ValueError 送出
          • ignore 無視される
        • dialect (略)
        • 戻り値 DictWriter オブジェクト
        >>> import csv
        >>> with open('01_sample.csv', mode='r', encoding='utf-8') as f:
        ...     for row in csv.DictReader(f):
        ...          print(row)
        ...
        {'id': '1', '都道府県': '東京都', '人口(人)': '13900000', '面積(km2)': '2194.05'}
        {'id': '2', '都道府県': '神奈川県', '人口(人)': '9200000', '面積(km2)': '2416.10'}
        {'id': '3', '都道府県': '千葉県', '人口(人)': '6200000', '面積(km2)': '5157.50'}
        {'id': '4', '都道府県': '埼玉県', '人口(人)': '7300000', '面積(km2)': '3797.75'}
        
      • DictWriter には、ヘッダーを書き込むメソッド writeheader(row) がある

        import csv
        
        data = [
            {'都道府県': '東京都', '人口密度(人/km2)': 6335},
            {'都道府県': '神奈川県', '人口密度(人/km2)': 3807},
            {'都道府県': '千葉県', '人口密度(人/km2)': 1202},
        ]
        
        with open('result.csv', newline='', mode='w', encoding='utf-8') as write_file:
            fieldnames = ['都道府県', '人口密度(人/km2)']  # ヘッダーの要素順を指定する
            writer = csv.DictWriter(write_file, fieldnames=fieldnames)
            writer.writeheader()  # DictWriterのメソッドwriteheaderを使用してヘッダー行を書き込み
            writer.writerows(data)  # データの一括書き込み
        
  • Dialect を推測して生成する Sniffer クラス

    クラスメソッド名 解説 戻り値
    sniff(sample, delimiters=None) sample のデータを解析し、推測結果を返す Dialect サブクラス
    has_header(sample) ヘッダーの有無を判定する bool

13.2 JSON を扱う json

JSON フォーマットを扱うための機能

  • JSON のエンコードとデコード

    • 関数 dump(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)

      • obj エンコード対象オブジェクト
      • skipkeys True の場合、辞書キーに str int float bool None 以外を指定しても TypeError を送出しない
      • ensure_ascii True の場合、非 ascii 文字列はエスケープされる (日本語などをそのまま出力したい場合は False にする)
      • check_circular True の場合、リストや辞書での循環参照がチェックされ無限再帰を防ぐ (False で循環参照が見つかると RecursionError)
      • allow_nan False の場合、許容範囲外 float (nan, inf, -inf) を検出すると ValueError
      • cls カスタマイズした JSONEncoder サブクラスを使用する場合に指定
      • indent インデントのスペース数を整数指定
      • separators セパレーター文字を (item_separator, key_separator) のタプルで指定
      • default シリアライズできないオブジェクトに対して呼び出す関数を指定
      • sort_keys True の場合、キーでソートされる
      • 戻り値 JSON 形式の str
      >>> import json
      >>> dbinfo = [{"db1": {"id": "user1", "pw": "pass1", "failover": True, "host": [{"ip": "192.168.0.1", "port": 8021},{"i\p": "192.168.0.2", "port": 8021}]}}, {"db2": {"id": "user2", "pw": "pass2", "failover": False, "host": [{"ip": "192.168\.0.3", "port": 8021}]}}]
      >>> print(json.dumps(dbinfo, indent=4))
      [
          {
              "db1": {
                  "id": "user1",
                  "pw": "pass1",
                  "failover": true,
                  "host": [
                      {
                          "ip": "192.168.0.1",
                          "port": 8021
                      },
                      {
                          "ip": "192.168.0.2",
                          "port": 8021
                      }
                  ]
              }
          },
          {
              "db2": {
                  "id": "user2",
                  "pw": "pass2",
                  "failover": false,
                  "host": [
                      {
                          "ip": "192.168.0.3",
                          "port": 8021
                      }
                  ]
              }
          }
      ]
      
    • 関数 loads(s, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)

      • s デコード対象のオブジェクト (str, bytes, bytearray)
      • cls カスタマイズした JSONDecoder サブクラスを使用する場合に指定
      • object_hook オブジェクトリテラルがデコードされた結果に対して呼ばれる関数を指定 (デコード結果が関数戻り値に置換される)
      • parse_float JSON に含まれる浮動小数点数 (文字列) を扱う関数を指定 (None なら float() が使用される)
      • parse_int JSON に含まれる整数 (文字列) を扱う関数を指定 (None なら int() が使用される)
      • parse_constant JSON に含まれる '-Infinity' 'Infinity' 'NaN' を扱う関数を指定
      • object_pairs_hook ペアの順序付きリストのデコード結果に対して呼ばれる関数を指定 (object_hook より優先される)
      • 戻り値 Python オブジェクト
      >>> jsonstr = '[{"name": "smith", "age": 41, "height": 167.5}, {"name": "sabakan", "age": 3}]'
      >>> pyobj = json.loads(jsonstr)
      >>> pyobj
      [{'name': 'smith', 'age': 41, 'height': 167.5}, {'name': 'sabakan', 'age': 3}]
      >>> type(pyobj)
      <class 'list'>
      >>> type(pyobj[0])
      <class 'dict'>
      >>> pyobj[0]
      {'name': 'smith', 'age': 41, 'height': 167.5}
      


    エンコード変換表

    Python → JSON
    辞書 オブジェクト
    リスト、タプル 配列
    文字列 文字列
    整数、浮動小数点数、
    intやfloatの派生列挙型
    数値
    True true
    False


    デコード変換表

    JSON → Python
    オブジェクト 辞書
    配列 リスト
    文字列 文字列
    数値 整数、浮動小数点数
    true True
    false False
    null None
  • JSON のエンコードとデコード (ファイルオブジェクト)

    • 関数 dump(obj, fp, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)
      • fp 書き込み先ファイルオブジェクト
      • 戻り値 None
    • 関数 load(fp, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)
      • fp 読み込み元ファイルオブジェクト
      • 戻り値 Python オブジェクト
  • JSON のコマンドラインインターフェースを提供している json.tool

    • JSON 文字列 (`curl で受け取ったレスポンスなど) を渡すだけで整形できる
    • python -m json.tool -h でヘルプ

13.3 INI ファイルを扱う configparser

Windows OS で設定ファイルとして多く使用される INI ファイル (他の場所でも多く使用されている) 、および INI ファイルに似た構造の設定ファイルを扱う

  • サポートされる INI ファイルの構造 (webドキュメントより)

    • 各セクションは [セクション名] で始まる領域
      • デフォルトではセクション名は改行を含まない任意の文字列
      • セクション名は大文字小文字が区別される
    • セクション内には、指定文字列 (デフォルトでは、 = および :) を使った キー/値 要素が並ぶ
      • キー、値はすべて文字列として扱われるが、取得時に変換もするメソッドが用意されている
        • getboolean() getint() getfloat()
      • キーは大文字小文字が区別されず、すべて小文字として扱われる (書き込み時も小文字)
    • キー、値の前後の空白は基本的に除去される
    • 値は複数行に渡って記述でき、その場合は2行目以降を1行目よりインデントさせる
    • コメントは行頭に特定文字 (デフォルトでは、# および ;) を付けた行全体 (インデントも可能)
    • 最初のセクション名は省略可能で、その場合は読み込み時にオプション allow_unnamed_section=True とすることで、無名セクションを扱える
      • 無名セクションへは、セクション名の代わりに configparser.UNNAMED_SECTION を使用してアクセスする
  • INI ファイルを読み込む

    ConfigParser インスタンスのメソッド

    メソッド 解説 戻り値
    read_string(string) 指定文字列を INI フォーマットとして解析する None
    read(filenames, encoding=None) 指定した INI ファイルを読み込む
    filenames にはリストで複数渡せる
    list (解析できたファイル名)
    sections() 読み込んだ INI 内のセクション名一覧を返す list (セクション名)
    options(section) 指定セクションのキー一覧を返す list (キー)
    • DEFAULT セクション
      • 特定セクションの存在しないキーを参照した場合、DEFAULT セクションのキーを参照して値が返される
  • INI ファイルの高度な利用 (値の補完)

    • INI ファイル内の他の場所に記載した内容を再利用 (値の補完 = interpolation) する

    • 値の補完方法クラスをコンストラクタに指定することで行う (クラスは configparser モジュール内)

      • ConfigParser(interpolation=BasicInterpolation) (指定しない場合と同じ)
      • ConfigParser(interpolation=ExtendedInterpolation)


      BasicInterpolation (セクション内の値補完. %(キー)s で参照する)

      [USER_A]
      home_dir = /home/user_a
      mail_dir = %(home_dir)s/mail
      group = Developer
      
      >>> config = ConfigParser()
      >>> config.read('config_interp.ini')
      ['config_interp.ini']
      >>> config['USER_A']['mail_dir']
      '/home/user_a/mail'
      


      ExtendedInterpolation (セクション外も補完可能: ${キー} ${セクション名:キー} で参照する)

      [USER_A]
      home_dir = /home/user_a
      mail_dir = ${home_dir}/mail
      group = Developer
      
      [USER_B]
      group = ${USER_A:group}
      
      >>> from configparser import ConfigParser, ExtendedInterpolation
      >>> config = ConfigParser(interpolation=ExtendedInterpolation())
      >>> config.read('config_exinterp.ini')
      ['config_exinterp.ini']
      >>> config['USER_B']['group']
      'Developer'
      

13.4 YAML を扱う PyYAML

  • YAML ファイルの読み込み

    関数名 解説 戻り値
    load(stream, Loader) YAML で記述されたファイルを読み込む Python オブジェクト
    load_all(stream, Loader) 「---」で区切られた YAML で記述されたファイルを読み込む Python オブジェクト (generator)
    safe_load(stream) load() に Loader=yaml.SafeLoader を指定したもの Python オブジェクト
    safe_load_all() load_all() に Loader=yaml.SafeLoader を指定したもの Python オブジェクト (generator)
    • 関数の引数 Loader に指定できるもの

      Loader 解説
      BaseLoader 基本的な YAML のみをロードする
      すべてのスカラーは文字列としてロードされる
      SafeLoader YAML のサブセットを安全にロードする
      FullLoader 基本的に YAML の全機能を受け入れるが、任意コード実行は一部制限 (デフォルト Loader)
      UnsafeLoader YAML の全機能を使用可能で、任意コード実行もできる
    • YAML でキー !!python/object: を指定して記載すると、任意の Python オブジェクトが生成可能

      • 生成オブジェクトから処理を実行可能
      • この機能への対応が、Loader によって制御されている


    単独ドキュメント

    ---
    database:
        host: localhost
        port: 3306
        db: test
        user: test
    smtp_host: localhost
    
    >>> import yaml
    >>> with open("sample1.yml", "r") as f:
    ...     y1 = yaml.safe_load(f)
    ...     y1
    ...
    {'database': {'host': 'localhost', 'port': 3306, 'db': 'test', 'user': 'test'}, 'smtp_host': 'localhost'}
    


    複数ドキュメント

    ---
    order: 1
    menu: ham
    ---
    order: 2
    menu: egg
    
    >>> with open("sample2.yml", "r") as f:
    ...     y2 = yaml.safe_load(f)  # 複数ドキュメントに対して load() はエラー
    ...     y2
    ...
    Traceback (most recent call last):
      ...(略)...
    yaml.composer.ComposerError: expected a single document in the stream
      in "sample2.yml", line 2, column 1
    but found another document
      in "sample2.yml", line 4, column 1
    
    >>> with open("sample2.yml", "r") as f:
    ...     y3 = yaml.safe_load_all(f)  # 複数ドキュメントに対しては load_all()
    ...     for y in y3:  # load_all() はジェネレーターを生成し、毎取得時にファイル参照するので、with 内で読み込みを完了させる
    ...         y
    ...
    {'order': 1, 'menu': 'ham'}
    {'order': 2, 'menu': 'egg'}
    
  • YAML ファイルの書き込み

    関数名 解説 戻り値
    dump(data, stream=None, Dumper=Dumper, **kwds) Python オブジェクトを YAML 文字列へ変換する 文字列または stream で指定した型
    safe_dump(data, stream=None, **kwds) dump() と同じだが、標準の YAML タグ以外の変換はエラー 文字列または stream で指定した型
    • **kwds 部分の代表的引数

      引数 解説
      indent インデントのスペース数を数値指定
      explicit_start True の場合、先頭に「---」が含まれる (デフォルトは False)
      default_flow_style True の場合 (デフォルト)、YAML のフロースタイル
      False の場合、ブロックスタイル
      (※動作確認時は、デフォルトが False になっていた)
      >>> hosts = {'web_server': ['192.168.0.2', '192.168.0.3'], 'db_server': ['192.168.10.7']}
      >>> with open('dump.yml', 'w') as f:
      ...     f.write(yaml.dump(hosts, default_flow_style=False))
      ...
      66
      
      db_server:
      - 192.168.10.7
      web_server:
      - 192.168.0.2
      - 192.168.0.3
      

13.5 Excel を扱う openpyxl

MS Excel の読み書きを Python で行うための機能を提供する
pip install openpyxl

  • Excel の読み込み
    • 関数 load_workbook(filename, read_only=False, use_iterators=False, keep_vba=False, guess_types=False, data_only=False)
      • filename Excel ファイルパス
      • read_only True の場合、読み取り専用となり編集できない
      • data_only True の場合、セルの値が式の場合に評価結果を取得する
      • 戻り値 Workbook オブジェクト
    • 参照
      • Workbook の属性 sheetnames で、ワークシート名のリストが取得可能
      • Workbook からはワークシート名をキーとして辞書と同様に Worksheet が取得可能
      • Worksheet からはセル名をキーとして辞書と同様に Cell が取得可能
        • メソッド cell(row=None, column=None, value=None) でも取得可能
      • Cell の値は属性 value で取得可能
  • Excel の書き込み
    • Cell に値を設定するには、辞書の値設定と同様に行う


      Workbook のメソッド

      メソッド名 解説 戻り値
      create_sheet(title=None, index=None) シートを index 位置に挿入する (0 なら先頭) Worksheet オブジェクト
      save(filename) ファイルパス filename へ Excel ファイルを保存する None
  • スタイルの適用
    • フォント
      • openpyxl.styles.Font オブジェクトを作成し、セルの font 属性に設定する
    • セルの色、模様 (塗りつぶし)
      • openpyxl.styles.PatternFill オブジェクトを作成し、セルの fill 属性に設定する
    • 罫線
      • openpyxl.styles.Border オブジェクトを作成し、セルの border 属性に設定する
        • Border に設定する各辺の属性は openpyxl.styles.Side オブジェクトを設定する
    • 文字位置
      • openpyxl.styles.Alignment オブジェクトを作成し、セルの alignment 属性に設定する
  • チャートの挿入
    • openpyxl.chart に様々なチャートあり (例 LineChart BarChart)

注意点

  • 表示形式が「ユーザー定義」のセルは注意、日付がシリアル値取得されるなどあり (openpyxl.utils パッケージに変換ツールなどが存在する)
  • Excel ファイルが他で開かれていると、保存時に PermissionError が発生する
  • data_only=True で式の解決値を取得できるのは、Excel ソフトで一度以上開いた場合のみ
    • プログラムで書き込んで、Excel で開かないまま読み込むと解決値は取得できない
    • これは Excel で開いた際に式解決が行われて結果がキャッシュされる為

13.6 画像を扱う Pillow

画像データ (JPEG, PNG など) を扱う機能 (拡大縮小、回転、色調変更、文字挿入 等) を提供する
pip install pillow
import PIL ※インポート時の指定に注意

  • 画像読み込み (PIL.Image モジュール)

    • 関数 open(file_path, mode='r', formats=None)
      • file_path 画像ファイルパス
      • mode モード指定だが、'r' 以外は使用できない
      • formats 開くファイルのフォーマットを制限したい場合は、フォーマットをタプルかリストで指定
      • 戻り値 Image オブジェクト
  • 画像のサイズを変更する、回転する

    • メソッド resize(size, resample=None, box=None, reducing_gap=None)
      • size リサイズ後の画像サイズ (ピクセル) をタプル (width, hight) で指定
      • resample リサンプリングフィルターを指定
        • PIL.Image.NEAREST 最近傍
        • PIL.Image.BILINEAR バイリニア
        • PIL.Image.BICUBIC バイキュービック
        • PIL.Image.LANCZOS ランチョス
        • PIL.Image.BOX
        • PIL.Image.HAMMING
      • 戻り値 Image オブジェクト
    • メソッド rotate(angle, resample=0, expand=0, center=None, translate=None, fillcolor=None)
      • angle 回転角度 (反時計回り)
      • 戻り値 Image オブジェクト
  • 画像を保存する

    • メソッド save(file_path, format=None, **params)
      • file_path 保存ファイルパス
      • format 保存する画像のフォーマットを指定 (省略時は file_path の拡張子から自動判別)
      • **param フォーマットごとに異なるオプション指定
      • 戻り値 None
  • テキストの埋め込み

    • ImageFont.truetype() でフォントオブジェクト (FreeTypeFont) を取得し、ImageDraw.Draw() で Image に対する ImageDraw オブジェクトを作成し、ImageDraw.text() で画像に埋め込む
    • 関数 ImageFont.truetype(font=None, size=10, index=0, encoding='', layout_engine=None)
      • font TrueType のフォントファイルを設定
      • size フォントサイズを指定
      • index 指定したフォントファイルに複数んおフォントが含まれている場合、ttc 番号を指定
      • 戻り値 フォントオブジェクト (FreeTypeFont)
    • 関数 ImageDraw.Draw(im, mode=None)
      • im Image オブジェクト
      • 戻り値 ImageDraw オブジェクト
    • メソッド ImageDraw.text(xy, text, fill=None, font=None, anchor=None, spacing=4, align='left', direction=None, features=None, language=None, stroke_width=0, stroke_fill=None, embedded_color=False)
      • xy テキストを埋め込む座標をタプル (x, y) で指定 (anchor 指定で実位置に変化あり)
      • text 埋め込むテキスト
      • fill テキストの色指定
      • font フォントオブジェクトを指定
      • 戻り値 None
    >>> from PIL import Image, ImageDraw, ImageFont
    >>> ifont = ImageFont.truetype(r'C:\Windows\Fonts\Meiryo UI\meiryo.ttc', size=40)
    >>> image = Image.open("GrandCanyon.jpg")
    >>> idraw = ImageDraw.Draw(image)
    >>> idraw.text((306,10), "グランドキャニオン", font=ifont, fill='red')
    >>> image.save('GrandCanyon_withText.jpg')
    


    元画像
    元画像


    テキスト埋め込み後画像
    テキスト埋め込み後

Tatsuya ISHIGAKI さんが1年以上前に更新 · 2件の履歴