Python 試験


≫ 参考資料



≫ 補足資料

 <ここから>

702頁 Chapter14 インターネット上のデータを扱う > urllib.request - URLを開く

 

<振り返り>

 urllib.parse - URLをパースする


第1章 Pythonの特徴

・コンパイルが不要

 

・インタープリター

 ・インタープリタがモジュールを検索するバスをモジュール検索パスという

 ・インタープリタが検索する順番は「ビルトインモジュール」→「sys.path変数で得られるディレクトリ」

 ・ビルトインモジュールとは組み込み関数のあるモジュールのこと。print()は組み込み関数で、正式には__builtins__.print()

 ・シンボリックリンクを置いてあるディレクトリはモジュール検索パスには入らない

 ・対話モードの終了方法には、関数の入力「quit()」によるものと、キー操作によるもの「ctrl + z」とがある

 ・「python -m timeit -h」を実行すると、timeitモジュールの詳細が出力さ

 ・対話モードでは、直前に評価した式が「_」に代入され、次の式で使用することができる 例 1 + 1; _ + 1

 

・処理のまとまりを表すとき、インデントを用いる

 

・Pythonという名の由来は英国BBCの番組「Monty Python's Flying Circus」にある

 

・他のプログラム言語で書かれたプログラムを使って機能拡張できる

 

・対話モード

 ・WindowsではコマンドプロンプトあるいはPowerShellで「python」と入力

 ・macOSではTerminal.appで「python3」と入力

 ・起動すると

  ・バージョン番号に続いてヘルプおよび著作権情報などを確認するためのコマンドが表示される

  ・一次プロンプトは「>>>」二次プロンプトは「...」

  ・二次プロンプトが表示されるとき、インデントは自動挿入されない

 ・Windows環境ではPythonの環境変数PATHに設定されていないと対話モードが起動されない

  Pythonをインストールする際の「Add Python 3.x to PATH」にチェックを入れる

  対話モードが起動しない場合はPythonの再インストールを行う

 

・文字コード

 ・ソースコードファイルはデフォルトではUTF-8でエンコードされたものとして扱う

 ・UTF-8以外の文字コードを使用するにはプログラムの先頭に以下を追加する。以下はshift_jisの場合

  # -*- coding: shift_jis -*-

 

・多重代入

 ・一度に複数の変数に値を代入する操作

a = 10
b = 20
a, b = b, a
print('%s %s' %(a, b))

Result

20 10

 

》補足

# タプルとリストを代入
a, b = (100, 200), [100, 200]
print('%s %s' %(a, b))

Result

(100, 200) [100, 200]

 

# 複数の変数に同じ値を代入
a = b = c = 100
print('%s %s %s' %(a, b, c))

Result

100 100 100

 

・コーディングスタイル

 ・可能であれがコメントは独立した行に書く

 ・ソースコードの幅が79文字を超えないように折り返す

 ・インデントにタブを使わず、空白4つをつかうことが推奨されている

 ・Pythonがプログラム言語として推奨しているスタイルガイドは通称「PEP8」と呼ばれる

  名前は「Python Enhancement Proposalsの8番目」であることが由来

 

・文字列の記述

 ・シングルクォート「'」、ダブルクォート「”」を使う

 ・関数やクラスの説明を書く際はトリプルクォート「'''」および「"""」を使う

 

・コメントの記述

 ・ハッシュ文字「#」を使う

 

・入力履歴ファイル

 ・自動生成されるファイル

 ・ファイル名「.python_history」

 ・ユーザーディレクトリーに作成される

 ・対話モードでカーソルキーの上下を押すと履歴として表示される

 

》補足

・モジュール検索パス

 ・インタープリタはimportしたモジュールを以下の順番で探す。

  ・ビルトインモジュール (インタープリタの組込モジュール) の中

  ・sys.path 変数で得られるディレクトリのリスト

 ・sys.path は以下の場所で初期化されている。

  ・入力スクリプトのあるディレクトリ

   ファイル名が指定されていない場合はカレントディレクトリ

  ・PYTHONPATH (ディレクトリ名のリスト)

  ・インストールごとのデフォルト

 ・シンボリックリンクを置いてあるディレクトリはモジュール検索パスに入らない。

 ・sys.path は初期化後にプログラムから改変可能。

 ・実行中のスクリプトのあるディレクトリは、検索パスの最初に置かれる。

  ・検索順序は標準ライブラリのパスより前。

   (注意)標準ライブラリのモジュールと同名のスクリプトを置くと、そちらが優先的にロードされてしまう。

Chapter2 コーディング規約

・PEP8

 ・コードのレイアウト

  ・インデント

   ・スペース4つ

   ・関数定義の引数などのカッコ内部で改行した場合、縦に揃える

def correct_ondent_1(var_one, var_two,
                     var_tree, var_four):
    print(var_one)

   ・辞書の要素は2行目スペース4つめから。閉じカッコは変数名に縦に揃える

num_list = [
    1, 2, 3,
    11, 12, 13
]

  ・空行

   ・トップレベルの関数やクラスの間は2行空ける

def empty_line_first():
    pass
 
 
def empty_line_second():
    pass

   ・クラス内のメソッドの定義は1行空ける

class EmptyLineClass:
    line_cnt = 0
 
    def next_empty_line():
        pass

  ・import文

   ・異なるモジュールはimport文を分ける

   ・次の順番でグループ化する(グループ間は1行空ける)

    1.標準ライブラリ

    2.サードパーティに関するもの

    3.ローカルのライブラリ

import os                           # ( 異なるモジュールはimport文を分ける )
import sys

from subprocess import Popen, PIPE  # ( 同じモジュールはimport文をまとめる )
 
import third_party                  # ( サードパーティのモジュールは標準ライブラリのあとにimportする )
 
import mymodule                     # ( ローカルのモジュールは最後にimportする )

  ・空白文字

   ・代入演算子や比較演算子などの両側に1つ空白文字を入れる

   ・カンマの後ろに空白文字を入れる

   ・閉じカッコなど終わりを表す文字の前に空白文字を入れない

i = i + 1
count_up += 1
 x = 1

if x == 4: 
    sum(x, y)

latte(milk[1], {art: 2})
latte( milk[ 1 ], { art: 2 } )     # ( 誤った例、カッコの前後に空白がある )

 ・コメント

  ・ブロックコメント

   ・コードと同じインデントで書く

   ・コメント自体は1つの#と1つの空白の後ろに書く

  ・インラインコメント

   ・コードとコメントの間に2つ以上のスペースを書く

   ・コメント自体は1つの#と1つの空白の後ろに書く

# ブロックコメント
correct_comment = "正しいコメント"

a = 1  # インラインコメント

  ・docstring

   ・関数やメソッドの説明はdefの直後に書く

   ・"""で始まり、"""で終わる行とする

   ・概要の詳細の間に1行空ける

def doc_string_sample():
    """関数の短い説明を書く

    短い説明と内容の間には空行を1行開ける
    内容を書く
    """

def doc_string_one_line():
    """1行で終わるdocstringの書き方"""

 ・命名規約

  ・パッケージ、モジュール - 小文字のみ

   クラス - 単語の先頭を大文字

   関数、変数、メソッド、インスタンス変数 - 小文字のみ。必要におうじてアンダースコアで区切る

   定数 - 大文字のみ

   例外 - 例外の名前の最後に "Error" をつけるべき

 ・PEP8のチェックツール Flake8(フレークエイト)

 ・PEP8の整形ツール Black


第2章 テキストと数の操作

・算術演算子の順序

 ・優先順位:べき乗「**」、乗算/除算、加算/減算の順になる

 ・除算の結果は浮動小数点になる 例「100 - 5**2 + 5 / 5 」の結果は「76.0」になる

 ・相手が整数でも浮動小数点で算術すると結果も浮動小数点になる 例「10 % 2.0 」の結果は「0.0」になる

 ・// は切り捨て除算。商の少数部分を切り捨てて整数部分を求める

 ・% は剰余。剰余とは商のあまり

 ・「48 // 6 // 4」は左から演算が行われ演算結果は「48 // 6 = 8 → 8 // 4 = 2」

  「2 ** 1 ** 3」は右から演算が行われ演算結果は「1 ** 3 = 1 → 2 ** 1 = 2」

 

・文字列リテラルの連結

 ・文字列リテラルとはシングルクォートあるいはダブルクオートで囲まれた値を指す

 ・print('Py thon')を実行した結果からは間のスペースが除外されPythonと出力される

 ・複数行で記述する場合は () で囲んで改行しながら列挙する

text = (
  "Usage: "
  "-h help "
  "-v version"
)
print(text)

Result

Usage: -h help -v version

 

・改行文字

 ・改行は\nで表され、1つの文字として扱われる。これを改行文字という

 ・トリプルクォート「"""」を使うとリテラル中の改行が改行文字として反映される

# 空白がそのまま出力。改行(\n)も出力される
text = """aaa
  bbb
    ccc\n  dd
"""
print(text)

Result

aaa

  bbb

    ccc

  dd

 

・len関数

 ・文字列の長さを返す

 

・文字列のスライス

 ・スライスとは指定した範囲の文字列を切り取る操作

 ・文字列 [ 開始位置 : 終了位置 ]

 ・スライスの位置    | a  |  b  |  c  |  d  |  e  |  f  |  g  |

  整数での指定の場合  0     1      2      3      4      5      6      7 

  負数での指定の場合   -7    -6     -5     -4     -3     -2    -1

 

》補足

word = "abcdefg"
print(word[2:5])   # cde
print(word[-5:-2]) # cde
print(word[:2])    # ab
print(word[2:-2])  # cde
print(word[::2])   # aceg
print(word[::-1])  # gfedcba

 

 ・f文字列(フォーマット済み文字列リテラル) ※Python3.6で導入

 ・f"文字列{値:書式指定文字列}" 例 price = 15000; print(f"価格:{price:7d}") ※07dで0埋めされる

 ・f文字列を使うことで文字列の中に式の値を入れられるようになる 例 a = 1; b = 1; print(f'{a + b}')

 ・式の後にフォーマット指定子のオプションを追加することで式の値にさまざまな書式を設定できる

 ・フォーマット指定子

  b  :値を2進数で出力する

  d  :値を10進数で出力する

  x  :値を16進数で出力する

  f   :値を与えられた精度まで少数で出力(.5fで少数第5位で丸める)

  % :値を100倍しパーセント記号が付いた形式で出力

 

》補足

name = "alice"
age = 30
print(f"Hello {name}. You are {age} years old.")

Result

Hello alice. You are 30 years old.

 

# フォーマット指定子
price = 15000
print(f"価格:{price:7d}")   # ( 数値7桁 右寄せ 空白埋め )
print(f"価格:{price:07d}")  # ( 0埋め )

text = "hello"
print(f"'{text:10s}'")       # ( 文字列10桁 左寄せ 空白埋め )

Result

価格: 15000

価格:0015000

'hello '

 

・formatメソッド ※Python3.6以前の方法

 ・"文字列{Field1}{Field2}{Field3}・・・".format(引数1, 引数2, 引数3)  Field:フォーマットフィールド {インデックス:書式指定}

 ・記述方法には3種類ある

  ①フォーマットフィールドに引数のインデックスを記述

   "spam: {0}, ham: {1}, eggs: {2}".format(x, y, z)

  ②空のフォーマットフィールドを使う。その場合は引数の値が順番に埋め込まれる

   "spam: {}, ham: {}, eggs: {}".format(x, y, z)

  ③フォーマットフィールドにキーワード引数を記述 

   "spam: {a}, ham: {b}, eggs: {c}".format(a=x, b=y, c=z)  この場合、キーワード引数はa, b, c

  ※フォーマットフィールドに引数の変数名を直接記述することはできない

 

》補足

# フォーマットフィールドにフォーマット指定子を指定
price = 15000
quantity = 100
print('数量:{1:05d}, 料金:{0:010.3f}'.format(price, quantity))  # ( インデックスは引数の並び順でなくてもOK )

Result

数量:00100, 料金:015000.000

# 文字列の繰り返し
print (3 * "y", "y" * 3, "ab" * 3)

Result

yyy yyy ababab

# 文字列はスライスで参照できるが更新はできない
str = 'abc'
print(str[0])  # a
str[0] = 'A'   # TypeError     
# 文字列も大小があり、大文字のほうが小文字より小さい。大小はunicodeで判定しord関数で取得できる
print(ord('A'))  # 65
print(ord('a'))  # 97

Chapter6 テキストの処理

・一般的な文字列操作

 ・文字判定

isalnum() 文字列が数字と文字のみの場合にTrueを返す
isalpha() 文字列が文字のみの場合にTrueを返す。日本語等の非ASCII文字列でも数字や記号を含まなければTrueを返す
isdecimal() 文字列が10進数を表す場合にTrueを返す
isdigit() 文字列が数字を表す文字のみの場合にTrueを返す
isidentifier() 識別子(変数名、関数名など)として使用できる文字列の場合にTrueを返す
isnumeric() 数を表す文字列の場合にTrueを返す。漢数字なども含まれる
isprintable() 印字可能な文字列の場合にTrueを返す
isspace() スペース、タブなどの空白文字の場合にTrueを返す
'a123'.isalnum()       # True
'あいう'.isalpha()     # True
'100'.isdecimal()      # True
'①②③'.isdigit()     # True
'a123'.isidentifier()  # True
100'.isnumeric()       # True
'abcd'.isprintable()   # True
'    '.isspace()       # True

 

  ・大文字・小文字

islower() 文字列がすべて小文字の場合にTrueを返す
isupper() 文字列がすべて大文字の場合にTrueを返す
istitle() 先頭のみ大文字であとは小文字の文字列の場合にTrueを返す
upper() 文字列をすべて大文字に変換
lower() 文字列をすべて小文字に変換
swapcase()  大文字を小文字に、小文字を大文字に変換
capitalize()  先頭1文字を大文字に、それ以外を小文字に変換
title()  単語ごとに大文字1文字+小文字の形式に変換
'abcd'.islower()                # True
'A100'.isupper()                # True
'A123'.istitle()                # True
'hello world'.capitalize()      # Hello world
'hello world'.title()           # Hello World

 

 ・置換

replace(old, new[, count]) oldをnewに変換した文字列を返す。countが指定された場合は先頭から指定された数だけ変換

 

  ・除去

strip([chars]) 文字列の先頭および末尾から指定した文字をすべて除去。charsが指定されてない場合は空白文字が削除される
lstrip([chars]) 文字列の先頭から指定した文字をすべて除去。charsが指定されていない場合は空白文字が削除される
rstrip([chars]) 文字列の末尾から指定した文字をすべて除去。charsが指定されていない場合は空白文字が削除される
removeprefix(prefix) 文字列の先頭からprefixで指定した文字列を除去
removesuffix(prefix) 文字列の末尾からsuffixで指定した文字列を除去
'hello world'.strip('hd')              # ello worl
'hello_world'.removeprefix('hello_')   # world

 

  ・0埋め

zfill(width)

長さがwidthになるように左に0を詰めた文字列に変換

'hello'.zfill(8)                       # 000hello

 

  ・サーチ

find(sub[, start[, end]]) 文字列中にsubが出現する位置を返す(戻り値:int)。存在しない場合は-1を返す
startswith(prefix[, start[, end]])

指定した接頭辞を持つ文字列かを調べる(戻り値:bool)。prefixにはタプルで複数の候補が指定できる。

start、endは調査する位置の指定に使用する

endswith(suffix[, start[, end]])  指定した接尾辞を持つ文字列かを調べる(戻り値:bool)。suffixにはタプルで複数の候補が指定できる。

start、endは調査する位置の指定に使用する

'abac'.find('a', 1)            # 2
'abac'.startswith(('a', 'b'))  # True
'abac'.endswith(('b', 'c'))    # True

 

 ・分割/結合

split(sep=None, maxsplit=-1)

文字列を分割する(戻り値:listで)。

デフォルトでは空白文字(半角スペース、全角スペース、改行、タブなど)で分割

join(iterable)  引数として指定した複数の文字列を結合(戻り値:str)
ls = "aa,bb,cc".split(',', 1)  # ['aa', 'bb,cc']
','.join(ls)                   # 'aa,bb,cc'

 ・文字列定数

import string

print(string.ascii_lowercase) # abcdefghijklmnopqrstuvwxyz ( 英小文字 ) print(string.ascii_uppercase) # ABCDEFGHIJKLMNOPQRSTUVWXYZ ( 英大文字 ) print(string.ascii_letters) # ( ascii_lowercase と ascii_uppercase を組み合わせたもの ) print(string.digits) # 0123456789 ( 10進数 ) print(string.hexdigits) # 0123456789abcdefABCDEF ( 16進数 ) print(string.octdigits) # 01234567 ( 08進数 ) print(string.punctuation) # !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ ( 記号 ) print(string.whitespace) # ( 空白:スペース、タブ、改行 (linefeed)、復帰 (return)、改頁 (formfeed) など ) print(string.printable) # ( ascii_letters, digits, punctuation, whitespace を組み合わせたもの )

 

 ・f-string(フォーマット済み文字列リテラル)

  ・{変数名=}で「変数名=値」の形式で出力される

var = "abc"
print(f'{var=}')

Result

var='abc'

 

・フォーマットの指定方法

 ・「:」の後ろに文字列変換のためのフォーマットを指定

:<30  :>30  :^30 指定した幅(ここでは30)で左寄せ /右寄せ /中央揃えする
:-<30 :->30 :-^30 左寄せ /右寄せ /中央揃えでスペースのかわりに指定した文字(ここでは-)で穴埋め
:b :o :d :x :X 2進数 /8進数 /10進数 /16進数(小文字) /16進数(大文字)に変換
:f 固定小数点の文字列に変換
:%

百分率での表記に変換

:, 数値に3桁ごとにカンマを挿入
:6.2f 表示する桁数を指定(ここでは6は全体の桁数、2は小数点以下の桁数)
:%Y-%m-%d %H:%M:%S 日付型特有の書式で、年月日などに変換
word = "abc"
f"{word:<5}"                  # 'abc  '
f"{word:^5}"                  # ' abc '
f"{word:-^7}"                 # '--abc--'
num = 0.045;   f"{num:6.2%}"  # ' 4.50%'
num = 1234567; f"{num:,}"     # '1,234,567'

 

 ・%演算子(別名:書式化演算子%)

  ・「文字列 % 値」のように書く。文字列リテラル中の値を埋め込む場合には%で始まる変換指定子を書く

'abc=%d' % 123    # 'abc=123'
'abc=%s' % 'def'  # 'abc=def'
a = 2; b = 3; '%d * %d = %d' % (a, b, a * b)  # '2 * 3 = 6'
'%(name)s likes %(language)s' % {'name': 'Taro', 'language': 'Python'}  # 'Taro likes Python' ( 辞書型もつかえる  )

第3章 リストの操作

・リストはPythonで複数の値を扱うための基本的なデータ構造

 

・データの種類は、整数、浮動小数点、文字列など

 

・リストの構造

           0    1    2    3    4 正のインデックス

  data = [ 1,   2,   3,   4,   5] 一つ一つが要素

       -5   -4   -3   -2   -1 負のインデックス

 

 ・角括弧(かくかっこ)とカンマを使う

 ・文字列と同様にインデックスで要素を参照

 ・文字列とは異なりインデックスで更新することが可能

 ・先頭のインデックスは0を使用

 ・末尾のインデックスは要素数-1

 

・リストのスライス範囲

 ・[ 開始位置:終了位置 ] で記述

 ・開始位置を省略すると先頭からになる

 ・終了位置を省略すると末尾までになる

 ・data[:] や data[1000:]、data[:1000]としてもエラーにならない

 

・リストに要素を追加

 ・リスト名.append(値) または リスト名 += [値]

 

・リストの長さを取得

 ・リストの長さとは要素数のこと。len関数で取得できる

 

・リストの入れ子

 ・リストの要素に別のリストを持つことを入れ子にするという [ [ 1, 2 ], [ 2, 3] ] 要素数は2

 

・入れ子の参照方法

 ・先頭の要素にインデックス[0]を使用。[ [ 1, 2 ], [ 2, 3] ]の [ 1, 2 ]のインデックスは[0]。 [ 1, 2 ]の1は[0][0]

 

・リストをスタックとして使う方法

 ・スタックとは複数の値を扱えるデータ構造の1つ

 ・リストと違うのは「要素を挿入するときも取り出すときも末尾から」という点(last-in, first-out)

 ・append(要素)で末尾に追加、pop()で末尾から削除

stack = [1, 2, 3, 4]
data = []
while stack:
  data.append(stack.pop())
print(stack)
print(data)

Result

[]

[4, 3, 2, 1]

 

・リストをキューとして使う方法

 ・キューとは複数の値を扱えるでデータ構造の1つ

 ・リストと違うのは「要素を挿入するとき末尾に追加れさ、取り出すときは先頭から削除される」(first-in, first-out)

 ・append(要素)で末尾に追加、pop(0)で先頭の要素を削除

que = [1, 2, 3, 4]
data = []
while que:
  data.append(que.pop(0))
print(que)
print(data)

Result

[]

[1, 2, 3, 4]

 

・リスト内包

 ・リストの角括弧内でfor文を使って記述したもの

 ・書式 [ 式 for 変数 in リストなど ]

data = []
for i in [1, 2, 3]:
  for j in [1, 2]:
    if i != j:
      data.append((i, j))
 print(data)

上記をリスト内包を使って記述

# 2重の内包。後のfor文が内側のループになる
print([(i, j) for i in [1, 2, 3] for j in [1, 2] if i != j])

Result

[ (1,2), (2, 1), (3, 1), (3, 2) ]

》補足:リストの更新

x = ['a', 'b', 'c']

x.append('d') # ['a', 'b', 'c', 'd'] ( 末尾に要素を追加 ) x.insert(2, 'd') # ['a', 'b', 'd', 'c'] ( 指定したインデックスに要素を追加 ) x.sort() # (要素を昇順にソート) y = sorted(x) # (ソート後のリスト生成。元リストは変更されない) x.sort(reverse=True) # ['c', 'b', 'a'] ( 要素を降順にソート ) x[1] = 'd' # ['a', 'd', 'c'] ( 要素を変更 ) x.remove('b') # ['a', 'c'] ( 左側から検索して最初の要素を削除 ) del x[2] # ['a', 'b'] ( 指定したインデックスを削除 )  y = x.pop(0) # x=['b', 'c'] y=a ( 指定したインデックスの要素を取り出す )

Chapter3 Python言語使用

・内包表記

  ・リスト内包表記の構文 

  ・[変数を使った処理 for 変数 in イテラブルオブジェクト]

  ・[変数を使った処理 for 変数 in イテラブルオブジェクト if 条件式]

 

 ・内容表記の可読性

  ・map()やfilter()といった組み込み関数があるが、それらの関数より内包表記を使うほうが可読性の高いコードが書ける

   map関数 :リストなどの各要素に何らかの関数を適用し別のオブジェクトを作成

   filter関数 :リストなどの各要素に何らかの関数を適用し、関数の戻り値がTrueとなる要素だけからなるオブジェクトを作成

arr = [1.4, 2.0, 3.5, 2.25, 1.98]

list(map(round, arr))                           # ( arrの中身を1つずつround関数で丸めたものをリストにする )
[round(n) for n in arr]                         # ( 上記を内包表記で置き換えたもの )

list(map(round, filter(lambda n: n > 2, arr)))  # ( map、filterは引数に関数をとるためlambdaを使用しているが可読性が下がる )
[round(n) for n in arr if n > 2]                # ( 上記を内包表記で置き換えたもの )

第4章 判定と繰り返し

《 判定 》

・整数の真偽の判定

 ・0が偽、それ以外は真

・短絡演算子

 ・A and B の場合、Aを判定して偽であればBを評価せずAの評価結果を返す。Aの判定が真であればBを評価してその評価結果を返す

 ・and がずっと続く場合、「最初に偽」になった評価結果を返す。すべて真の場合は最後の評価結果を返す

 ・or がずっと続く場合、「最初に真」になった評価結果を返す。すべて偽の場合は最後の評価結果を返す

var1 = 0 and 1 and 2   # ( 最初の 0 の評価結果を返す )
var2 = 1 and 1 and 2 # ( 最後の 2 の評価結果を返す ) var2 = 0 or 1 or 2 # ( 2番目の 1 の評価結果返す ) print(var1, var2, var3)

Result

0 2 1

 

・None

 ・値が何も存在しない状態を表す

 ・最も適切な判定は if val is None:

 ・if val == None: でも判定できるが is None: より実行時間がかかるため最適とはいえない

 

《 繰り返し 》

・range関数

 ・range(stop) または range(start, stop) または range(start, stop, step)

 ・start, stop, step には整数を指定

 ・startから始まりstopの直前まで、stepごとに整数を順番に取得

 ・start省略時は0から始まる

 ・step省略時は1ごと

 

・for文

 ・breakはループを直ちに終了する

 ・continueは現在のループを中止して次のループに進む

 ・for文でディクショナリのキーと値を同時に取得するには itemsメソッドを使う

# itemsメソッドでディクショナリからkeyとvalueを取得
data = {'case':'orga', 'cnt':0.0}
for key, val in data.items():
    print(key, val)

Result

case orga

cnt 0.0

 

 ・for文とenumerate関数を組み合わせると反復可能体(繰り返し可能なもの)からインデックスと要素を同時に取得できる

   反復可能体:リスト、タプル、ディクショナリ、文字列などのデータ型

# enumerate関数で反復可能体からインデックスと要素を同時に取得
for i, c in enumerate("AB"):
    print(i, c)

Result

0 A

1 B

# ディレクトリに対するenumerateの返し値は、keyがenumerateの生成したインデックス番号、valueがディレクトリのkeyを返す
dic = {'A1':'red','A2':'blue','A3':'white'}
for key, val in enumerate(dic):
    print(key, val)

Result

0 A1

1 A2

2 A3

 

 ・for文とzip関数を使うと複数の反復可能体から並列で要素を取得できる

for n, c in zip([1,2,3],["1","2","3"]):
    print(c, n, c*n)   # ( c*n:文字列のn倍は文字列をn個並べたものになる )

Result

1 1 1

2 2 22

3 3 333

 

# その他のアンパックパターン
data = [[1, 3, 5], [4, 9, 25], [8, 27, 125]]
res = [[row[i] for row in data] for i in range(3)]  # ( 後者のfor文の繰り返し回数毎に、前者のfor文の全要素を処理 )
print(res)

res = list(zip(*data))  # ( これでも上記と同じ結果が得られる )

Result

[[1, 4, 8], [3, 9, 27], [5, 25, 125]]

 

・sorted関数とreversed関数

 ・sorted関数を使うと昇順にソートしたリストを取得できる

 ・reversed関数を使うとリストや文字列などから逆順にしたオブジェクトを取得できる

print(sorted("EAT"))
print(reversed(sorted("EAT")))  # ( このままでは確認できないので下記のようにリスト化する )
print(list(reversed(sorted("EAT"))))

Result

['A', 'E', 'T']

<list_reverseiterator object at 0x0000029A484DB970>

['T', 'E', 'A']

 

》補足

・イテレーターとは

 リストなどの複数の要素をもったデータ型に対して、順番にデータを取り出す機能

 for文ではリストを引数に使用した際に内部的に実行される

 

・イテラブル(反復可能体)とは

 for文などで繰り返し可能なオブジェクト。リストやタプルなど

 

・for-else構文

 ・forループが正常に完了するとelseブロックが実行される

 ・forループが一度も実行されなかった場合でもelseブロックは実行される

 ・break文でループが途中で終了した場合、elseブロックは実行されない

for n in range(2, 10):
    for x in range(2 ,n):
        if n % x == 0:
            print(n, 'equals', x, '*', n//x)
            break    # ( 内側のループを抜ける )
    else:
        print(n,'is a prime number')
        continue
    break    # ( 外側のループを抜ける )

Result

2 is a prime number

3 is a prime number

4 equals 2 * 2

Chapter9 データ型とアルゴリズム

・sorted() 組み込み関数

 ・引数に与えたイテラブルオブジェクトをソートし、結果をリスト型で返す

 ・引数に与えたオブジェクトは変更されず、新たなリストが生成される

seq = [0, 4, 1, 2, 3, 5]
sorted(seq)                          # [0, 1, 2, 3, 4, 5]  ( ソートを行う )
sorted(seq, reverse=True)            # [5, 4, 3, 2, 1, 0]  ( 降順ソート。もとのリストは変更されない )

# リストの要素が文字列の場合
seq_str = ["spam", "ham", "egg"]
sorted(seq_str)                      # ['egg', 'ham', 'spam']
sorted(["spam", "ham", 10])          # TypeError  ( 文字列と数値は比較ができない )

# リスト型以外
sorted((0, 4, 1, 2, 3, 5))           # [0, 1, 2, 3, 4, 5]  ( タプル型をソートしてもリスト型を返す )
sorted({'a': 1, 'c': 2, 'b': 3})     # ['a', 'b', 'c']  ( 辞書型の比較はキーをソートしてキーのリストを返す )
sorted({'a': 1, 'c': 2, 'b': 3}.items())  # [('a', 1), ('b', 3), ('c', 2)]  ( 辞書型のキーと値のペアをリストで返す )
sorted({8, 3, 4, 3})                 # [3, 4, 8]  ( 集合型も要素をソートしてリスト型を返す )
sorted("初のPy3コード")              # ['3', 'P', 'y', 'の', 'コ', 'ド', 'ー', '初']  ( 文字列は1文字ずつUnicode順にソート )

 

・reversed() 組み込み関数

 ・引数に与えたオブジェクトは変更されない

 ・シーケンス型の要素順を逆にするだけで、ソートをするわけではない

 ・シーケンス型とは、リスト型やタプル型、range型など、順番を持つコンテナーをいう

 ・戻り値はリストではなく、専用のイテレーター

seq = [0, 4, 1, 2, 3, 5]
rev_seq = reversed(seq)  # ( リストを逆順にする )
rev_seq                  # <list_reverseiterator object at 0x7f7f78231130>  ( 専用のイテレーターが返ってくる )
list(rev_seq)            # [5, 3, 2, 1, 4, 0]  ( リストに変換して出力 )
list(rev_seq)            # []  ( rev_seqはイテレーターなので2回目は空リストとなる )

 

・リストのsort()メソッド、reverse()メソッド

 ・リストのsort()メソッドとreverse()メソッドは、もとのリストを変更する破壊的操作。実行前後でデータが異なっている事に注意が必要

seq = [0, 4, 1, 2, 3, 5]
seq.sort()               # ( ソートを実行、戻り値がNone )
seq                      # [0, 1, 2, 3, 4, 5]  ( もとのリストを確認するとソートされている )

seq2 = [0, 4, 1, 2, 3, 5]
seq2.sort(reverse=True)  # ( reverseにTrueを指定して、降順ソートを実行 )
seq2                     # [5, 4, 3, 2, 1, 0]

seq = [0, 4, 1, 2, 3, 5]
seq.reverse()            # ( リストを逆順に変更する。戻り値はNone )
seq                      # [5, 3, 2, 1, 4, 0]  ( もとのリストが逆順になっている )

 

・Key 引数

 ・key引数には、関数などの呼び出し可能オブジェクトを指定できる

 ・指定された関数などを使い、要素を変換などしてから小なり(<)で比較する

seq_str = ["B", "D", "a", "c"]  # ( 大文字小文字混じりの文字列のリスト )
sorted(seq_str)                 # ['B', 'D', 'a', 'c']  ( keyを指定せずにソート )
sorted(seq_str, key=str.lower)  # ['a', 'B', 'c', 'D']  ( 小文字に変換して比較した結果 )

第5章 関数

・関数の定義

 ・関数に定義する引数を「仮引数(parameter)」と呼ぶ

 ・def 関数名(仮引数1, 仮引数2, …)

 

・関数の呼び出し

 ・関数を呼び出す際に指定する引数を「実引数(argument)」と呼ぶ

 ・関数名(実引数1, 実引数2, …)

 ・関数呼び出しで()は省略できない

 ・関数そのものを変数に代入して呼び出す方法もある

def greeting(a):
    return (a)

x = greeting  # ( 関数を変数に代入 )
y = x("Hello")
print(y)

Result

Hello

 

・関数の変数

 ・ローカル変数は、その関数内で定義する必要がある

 ・同名の変数が関数の内側と外側で定義されていても、それぞれ別の変数として扱われる

 ・関数内で定義されている変数は関数の外側では参照できない

 

・global・nonlocal  

 ・グローバル変数はモジュールのトップレベルで定義される変数のこと。この変数はモジュール内の任意の位置から参照できる。

  関数内でグローバル変数に値を代入するにはglobal文で示す必要がある

x = 100  # ( グローバル変数 )

def do_global():
    global x  # ( グローバル変数であることを示す )
    x = 200

do_global()
print(x)

Result

200

 

 ・関数の中で別の関数を定義し、その内部から外部の関数の変数を変更するにはnonlocal 文で示す必要がある

def outer():
    x = 10  # ( outer関数のスコープにある変数 )
    def inner():
        nonlocal x  # ( outer関数のxを変更する )
        x = 20
    inner()
    print(x)  

outer()

 

・関数の引数

  ・キーワード引数

  ・「キーワード=値」をキーワード引数という

  ・値だけの引数を位置引数という

  ・キーワード引数の後に位置引数は与えられない

  ・存在しないキーワード引数は与えられない

  ・位置引数で指定済みの引数に対して、キーワード引数を指定できない

  ・関数定義が位置引数に対して、関数呼び出し側をキーワード引数で設定すれば引数を記述する順番は任意

 

 ・引数のデフォルト値

  ・def 関数名(引数=デフォルト値):

  ・引数にはデフォルト値を設定できる

  ・関数の実行時に値を与えられなくてもデフォルト値が関数の中で使われる

  ・仮引数にデフォルト値を指定したら、それ以降の仮引数にもデフォルト値を指定する必要がある

  ・引数のデフォルト値は関数が定義された時点で評価され、関数の実行時に再評価はされない

def_message_1 = "Hello"

def message(message_1=def_message_1, message_2=""):  # ( 関数が定義された時点で評価 )
    print(f"{message_1} {message_2}")

def_message_1 = "こんにちは"                         # ( デフォルト値には影響しない )
message_2 = "word"

message(message_2=message_2)                        # ( 関数の実行時に再評価はされない )

Result

Hello word

 

  ・引数のデフォルト値をリストにすると、その引数に値が加えられるたびにデフォルト値も変更される

def func(num, def_list=[]):
    def_list.append(num)
    return def_list

print(func(1))           # ( デフォルト値が[1]に変更される )
print(func(2, [3, 4]))   # ( デフォルト値なし。[3, 4]に2が加えられる )
print(func(3))           # ( デフォルト値[1]に3が加わり、デフォルト値が[1, 3]に変更される )

Result

[1]

[3, 4, 2]

[1, 3]

 

 ・「*」がついた仮引数

  ・*  が先頭に付いた仮引数には、指定済みの実引数を除く位置引数のリストおよびタプルが入る

  ・**が先頭に付いた仮引数には、指定済みの実引数を除くキーワード引数のディクショナリが入る

def func(name, *args, **kwargs):   # ( 「*」がついた仮引数。argsはタプル )
    print(name, args, kwargs)

func("abc", "def", "ghi", kw1="123", kw2="345")

Result

abc ('def', 'ghi') {'kw1': '123', 'kw2': '345'}

 

 ・「*」がついた実引数(アンパックと呼ぶ)

  ・リストおよびタプルは、「*」を先頭に付けることで要素を位置引数に展開して関数に渡せる

  ・ディクショナリは「**」を先頭に付けることで、キーワード引数として指定できる

  ・アンパックとはリストやタプルから1つ1つの要素を取り出して変数などに代入することをいう

def concat(*args, sep="/"):       # ( args:実引数はリスト型だが受け取った仮引数はタプル )
    return sep.join(args)

words = ["spam", "ham", "eggs"]
option = {"sep": "&"}
print(concat(*words, **option))    # (「*」がついた実引数(アンパックと呼ぶ) )

Result

spam&ham&eggs

 

・lambda(ラムダ)式

 ・lambda 引数: 式

 ・無名関数と呼ばれる種類の関数

 ・単一の式しか持てない

 ・式の結果が返り値になる

func = lambda a, b: (b + 1, a *2)
x, y = 1, 2
x, y = func(x, y)
print(x, y)

Result

3 2

 

 ・sortに関数を渡してリストのソート基準を設定。関数にlambdaを使って各要素のインデックス「1」でソート

# リスト
lst = [(3, 'b'),(1, 'c'),(2, 'a')]
lst.sort(key =lambda arg : arg[1])
print(lst)

Result

[(2, 'a'), (3, 'b'), (1, 'c')]

# ディクショナリー
a = {"apple": 5, "banana": 2, "cherry": 8}
b = sorted(a.items(), key=lambda x: x[1])
print(b)

Result

[('banana', 2), ('apple', 5), ('cherry', 8)]

 

 ・map関数はfor文を使わなくてもリストの全要素にアクセスできる map(lamba 引数: 戻り値, iterable)

lst = list(map(lambda a: a**3, range(3)))
print(lst)

Result

[0, 1, 8]

 

》補足

・ドキュメンテーション文字列(docstring)

 ・docstringはクラスや関数を説明するためのコメント

 ・1行目にはクラスや関数の目的などを書く。1行空けて呼び出し方や引数などの詳細を書く

 ・docstringは__doc__という属性で参照できる

def func(x, y):
    """ 2つの引数を乗算する関数
    
    x, yは整数であること
    """
    return x * y

print(func.__doc__)

 

・関数アノテーション

 ・関数の引数や返り値にアノテーション(注釈)を記述できる

 ・型は関数アノテーション、詳しい説明文はdocstringと併用して記述する場合が多い

 ・引数名のあとの : 式がそれぞれの引数に対するアノテーション

 ・) と末尾の : の間の -> 式が返り値に対するアノテーション

 ・デフォルト値はアノテーションのあとに記述する

 ・アノテーションはあくまで注釈で、それをもとに特別な処理が行われることはない

 ・アノテーションとして型を指定することもできるが、実行時に型チェックが行われたりはしない

 ・関数アノテーションは__annotations__属性に辞書(dict)として格納されている

def func(x: 'for_x', y: 'for_y' = 1) -> 'for_return':
    return x * y

print(func('abc', 3))

print(func.__annotations__, func.__annotations__['x'])

Result

abcabcabc

{'x': 'for_x', 'y': 'for_y', 'return': 'for_return'} for_x

 

・名前空間

 ・変数や関数の名前が所属している場所のこと。 変数や関数が所属する場所、つまりモジュールやクラスが名前空間になる。
  異なる名前空間にある同じ名前のオブジェクトには何の関係もない

Chapter3 Python言語使用

・関数の引数

 ・位置引数

  ・関数呼び出し時に先頭から順に引数の位置を対応させて渡される

  ・仮引数と実引数の数を一致させる必要がある

 ・キーワード引数

  ・実引数を「kwarg=value」という形式で仮引数名を指定して渡す

  ・関数定義の仮引数の順番どおりに実引数を渡す必要がない

 ・位置引数とキーワード引数の混在

  ・関数呼び出し時、位置引数とキーワード引数が混在する場合、位置引数を先に置く必要がある

 ・デフォルト値付き引数

  ・関数呼び出し時、実引数を省略したときに使用されるデフォルト値を仮引数に設定できる

  ・デフォルト値は変更不可なオブジェクト(文字列、数値、タプル)を指定する

  ・仮引数にデフォルト値を指定したら、それ以降の仮引数にもデフォルト値を指定する必要がある

def sample_func(param1=1, param2, param3=3):  # ( Param2がSyntaxErrorになる )
    print(f'{param1}, {param2}, {param3}')

 ・可変長位置引数

  ・仮引数に「*」を付けると可変長の位置引数(任意の数の引数)を定義できる

  ・慣例として仮引数には*argsという名前が使われることが多い

  ・*argsは複数の引数をタプルとして受け取る

  ・*argsはほかの位置引数よりも後ろに指定する必要がある

  ・可変長位置引数の前にデフォルト値付き引数を定義しない

  ・可変長位置引数に対応した組み込み関数ではリストやタプルに「*」を付けて渡す

lst = [1, 2, 3]
print(*lst) 

Result

1 2 3

 ・可変長キーワード引数

  ・仮引数に「**」を付けると可変長のキーワード引数を定義できる

  ・慣例として仮引数には**kwargsという名前が使われることが多い

  ・**kwargsは複数のキーワード引数を辞書として受け取る

  ・**kwargsは複数は一番最後に指定する必要がある

 ・上記4つを混在させる場合の順番

  1. 位置引数

  2. 可変長位置引数

  3. デフォルト値付き引数

  4. 可変長キーワード引数

 ・キーワード専用引数

  ・キーワードを強要したい際などに使う

  ・「*」のあとに定義された引数は、キーワード引数として指定しなければ呼び出せない

def sample_func(param1, *, keyword1):
    print(f'{param1}, {keyword1}')

sample_func(1, keyword1=False)

 ・位置専用引数

  ・「/」の前に定義された引数は、位置引数として指定しなければ呼び出せない

def add(x, y, /):
    return x + y

add(1, 2)

 

・アンパック

 ・タプルやリスト、辞書などの複数の要素を持つものを展開して、複数の変数に代入できる

tp = (1, 2, 3)
a, b, c = tp                 # ( print(a, b, c) → 1 2 3 )

di = {'a':1, 'b':2, 'c':3}
a, b, c = di                 # ( print(a, b, c) → a b c )
a, b, c = di.values()        # ( print(a, b, c) → 1 2 3 )

tp = (1, 2, (3, 4, 5))
a, b, c = tp                 # ( print(a, b, c) → 1 2 (3, 4, 5) )
a, b, (c, d, e) = tp         # ( print(a, b, c, d, e) → 1 2 3 4 5 )
a, b, c, d, e = tp           # ( ValueError )

 ・アスタリスクを使ったアンパック

  ・代入される側の変数名の前に「*(アスタリスク)」を付けると、要素がその変数にまとめて代入される

  ・「*」付ける変数はどの変数でも問題ないが1つの変数にしか適用できない

tp = (1, 2, 3, 4)
a, *b, c = tp       # ( print(a, b, c) → 1 [2, 3] 4 )
*a, b, c = tp       # ( print(a, b, c) → [1, 2] 3 4 )
*a, *b, c = tp      # ( SyntaxError )
a = [[1, 2], [4, 5]]
print( *[y for x in a for y in x], sep="\n")

Result

1

2

4

5

 ・関数の引数のアンパック

  ・関数の実引数でタプルやリストを渡す際に「*」を付けると、中身を展開して渡すことができる

def sample_func(param1, param2, param3):
    print(f'{param1}, {param2}, {param3}')  # 1, 2, 3

args = [1, 2, 3]
sample_func(*args) 

  ・辞書を展開して仮引数に渡す場合は実引数に「*」を2つ付ける

def display_user(name, age, email):
    print(f'{name}, {age}, {email}')

user = {'name': 'John', 'age': 30, 'email': 'John@example.com'}
display_user(**user)  # ( キーワード引数での呼び出しと同じ display_user(name='John', age=30, email='John@example.com') )

Chapter5 型ヒント

 

・型ヒントはアノテーションであるため、プログラムの実行時に型はチェックされない

・型ヒントはコードの書きやすさ、読みやすさ、そしてバグを防止するためにある

 

・変数への型付け

name: str = "たろう"  # ( 変数nameはstr型 )
age: int = 9          # ( 変数ageはint型 )
student: bool = True  # ( 変数studentはbool型 )

・関数の引数、戻り値の型付け

def five_years_later(age: int) -> int:               # ( 関数の引数と戻り値にint型を指定 )
def five_years_later_students(age: int = 7) -> int:  # ( 引数のデフォルト値を指定 )
def say_hello(name: str) -> None:                    # ( 戻り値がない場合、Noneを指定 ) 

・コンテナーの型付け

hobby: list = ["ゲーム", "マンガ"]
food: tuple = ("バナナ", "ハンバーグ")
favorite: dict = {"study": "プログラミング", "movie": "モンティパイソン"}
like_num: set = {1, 3, 5}

・コンテナー内の要素の型付け

hobby: list[str] = ["ゲーム", "マンガ"]                                              # ( listの要素の型にstrを指定 )
favorite: dict[str, str] = {"study": "プログラミング", "movie": "モンティパイソン"}  # ( dictのキーと値の型にstrを指定 )
like_num: set[int] = {1, 3, 5}                                                       # ( setの要素の型をintで定義 )

 ・タプル要素への型付けする際の注意

  ・タプル要素のすべてに対して型を指定する必要がある

  ・同じ型の場合は、「...」で繰り返しを省略できる tuple[str, ...]

 

・ユーザー定義クラスを型として利用する

 ・自分で定義したクラスを型として利用できる

from dataclasses import dataclass
from operator import attrgetter

@dataclass
class Book:
    name: str
    author: str
    price: int

def books_a_bargain(book_list: list[Book]) -> Book:  # ( Bookオブジェクトのリストを受け取り、Bookオブジェクトを返す )
    """priceでソートして一番安い本を返す"""
    return sorted(book_list, key=attrgetter("price"))[0]

py_books = [
    Book("ハッカーガイド", "terapyon", 2992),
    Book("ゼロから", "takanori", 3200),
    Book("スタートブック", "shingo", 2750),
]

value_book: Book = books_a_bargain(py_books)  # ( value_bookをBookクラスで型付け )
print(value_book)                             # ( Book(name='スタートブック', author='shingo', price=2750) )

 

・typingモジュール

 ・型ヒントをサポートする標準ライブラリ。さまざまな型を付けることができる

 ・関数やその戻り値の想定外の利用によるバグを防ぐことができ、生産性が向上する

 ・IDEやエディターでの入力補完があり、実装のスピードが加速する

 

 ・Union 複数の型を指定できる

from typing import Union

def address_code(number: Union[int, str]) -> int:
    pass

your_code: int = address_code(1000001)  # ( 数値を渡せる )
my_code: int = address_code("1000001")  # ( 文字列を渡せる )

 ・Optional 指定した型とNoneを指定できる。以下のコードではprice変数に数値またはNoneを指定できる

from typing import Optional

price: Optional[int]

 ・Python 3.10からは複数の型を許可する「型名 | 型名」と書くことができる。typingモジュールのインポートは不要

  Python 3.7から3.9でも「from __future__ import annotations」で「|」が利用できる

  以下のコードは、さきほどのUnion、Optionalで書いた例を「|」で書き直したもの

def address_code(number: int | str) -> int:
    pass

price: int | None

 ・Literal 特定の値のみを許可する定義

from typing import Literal

FILETYPE = Literal["csv", "json", "xml"]  # ( ["csv", "json", "xml"]のみを許可 )
def access_file(file: str, file_type: FILETYPE):
    pass

access_file("wheather.csv", "csv")        # ( FILETYPEに含まれる値のためOK )
access_file("wheather.html", "html")      # ( FILETYPEに含まれない値のためNG )

 

 ・Any 任意の型を許可する

  ・Anyで定義しておくことであらゆる型を受け付けることができる

from typing import Any

user_input: Any = util_valid(args)            # ( 型付けされていない関数の戻り値を受け取る )

def process_by_type(user_input: Any) -> Any:  # ( 関数の引数や戻り値にAnyを指定する )
    if isinstance(user_input, str):
        pass

 

 ・TypedDict 辞書のキーと値の型を指定する

  ・TypedDictとdataclassの使い分けとして、辞書として利用したい場合はTypedDictを、クラスとして利用したい場合には
   dataclassを使うとよい

from typing import TypedDict

class BookDict(TypedDict):  # ( TypedDictを継承したクラス )
    name: str
    author: str
    price: int

# BookDict辞書クラスで型付けした辞書を作成 fav_book: BookDict = {"name": "スタートブック", "author": “shingo”, "price": 2750}

 

・静的型チェックツール ☆ 試験対象外 

 ・Pythonは動的型付け言語(変数の型を実行時に決定する方式で、プログラマーが明示的に変数の型を宣言する必要がない)

 ・型ヒントの利用に不整合があっても、プログラム実行時に型ヒントを使ったチェックはされずエラーにならない

 ・不整合があるコードに対して、静的型チェックツール(mypy)を利用することで不整合を検出できる

 

 ・mypy

  ・mypyのインストール pip install mypy

  ・mypyは、型ヒントが正しく利用されているかチェックし、エラーを出力する

  ・エラーメッセージは左から順に「ファイル名:行番号: エラー種別: エラー内容」が出力

# エラーがある場合
$ mypy mypy_check.py
mypy_check.py:2: error: Incompatible types in assignment (expression has type "int", variable has type "str")  
# age: int = "18" # エラーがない場合 $ mypy mypy_check_ok.py Success: no issues found in 1 source file

  ・mypyのオプション

  ・mypyのオプションは、設定ファイルやコマンドラインで利用できる

   コマンドライン:--disallow-any-generics 

   設定ファイル :  disallow_any_generics

  ・厳しくするオプションとゆるくするオプションがある

  ・各オプションをTrueに設定すると有効になる

 


第6章 その他のコレクションの操作

・collections.deque

 ・キューのように扱えるデータ構造

 ・append() でキューの末尾に要素を追加

 ・pop()     でキューの末尾の要素を取り出す

 ・appendleft()  でキューの先頭に要素を追加

 ・popleft()   でキューの先頭の要素を取り出す

# deque(デック) スタックやキューとして利用するならリストより高速
from collections import deque

d1 = deque([1, 2])
d1.append(3)
d1.popleft()
d1

Result

deque([2, 3])

 

・タプル

 ・タプルの定義は、カンマ区切りの要素を括弧「()」で囲む tup = ("spam", "ham")

 ・() を省略しても定義可能 tup = "spam", "ham"

 ・要素が1つの場合は末尾にカンマを書く(要素が1でカンマがないと文字列になる) tup = "spam", 

 ・tuple関数を使う場合、その引数はリストなどの反復可能体である必要がある tup = tuple(["spam", "ham"])

 

・リストとタプル

 ・リストとタプルには数値や文字列など異なるデータ型の要素を格納できる

 ・リストは既に存在する要素の値を変更可能だが、タプルは変更不可

 ・リストとタプルはlen関数で要素数を取得できる

 

・set

 ・setとは集合を扱うデータ型のこと

 ・要素を重複しないように保持する

 ・2つのset同士で和集合や差集合といった集合演算を行える

 ・set関数によって定義する

 ・addメソッドで要素を追加できるが、追加した順序を保持しない

 ・removeメソッドで要素を削除できる

 ・集合(メソッドも使用可能)

  s1 - s2 差集合(s1からs2の要素を除いた集合) differenceメソッド  

  s1 ^ s2 対称差集合(どちらか一方にだけ含まれる要素の集合) symmetric_differenceメソッド

  s1 | s2 和集合 unionメソッド

  s1 & s2 積集合 intersectionメソッド

se1 = set([2, 3, 1])
se2 = set([3, 1, 4, 4])
se1.add(0)
se1.remove(3)
print(se1, se2)                                  # {0, 1, 2} {1, 3, 4}
print(se1 - se2, se1.difference(se2))            # {0, 2}  ( 差集合 ) 
print(se1 ^ se2, se1.symmetric_difference(se2))  # {0, 2, 3, 4}  ( 対称差集合 )
print(se1 | se2, se1.union(se2))                 # {0, 1, 2, 3, 4}  ( 和集合 )
print(se1 & se2, se1.intersection(se2))          # {1}  ( 積集合 )
print(1 in se1)                                  # True  ( in演算子 )

 

 ・ディクショナリ

 ・変数 = {キー1: 値1, キー2: 値2, …}

 ・リストはインデックスを使って参照・更新するのに対して、ディクショナリではキーを使用する

 ・キーには文字列、タプル、数値も指定可能。可変体であるリストはキーに指定できない

 ・ディクショナリは変更可能(mutable)であるが、キーの型は変更不能(immutable)であり、その値は一意でなければならない

 ・要素の追加 ディクショナリ[キー] = 値 値の変更も同様

 ・要素の削除 del ディクショナリ[キー]

 ・in演算子を使ったキーの存在確認

  ・ディクショナリに対してin演算子を使う

  ・ディクショナリのkeysメソッドでkeyの一覧を取得。これに対してin演算子を使う

  ・list関数にディクショナリを指定するとキーを要素とするリストが生成される。これに対してin演算子を使う

dic = {"apple": 120, "banana": 150}

dic["orange"] = 100
del dic["banana"]

print(dic)                                 # {'apple': 120, 'orange': 100}
print([x for x in dic.keys()])             # ['apple', 'orange']
print([x for x in dic.values()])           # [120, 100]
print([(x, y) for x, y in dic.items()])    # [('apple', 120), ('orange', 100)]

print("apple" in dic)                      # True
print("apple" in dic.keys(), dic.keys())   # True dict_keys(['apple', 'orange'])
print("apple" in list(dic), list(dic))     # True ['apple', 'orange']

 

 ・ディクショナリの内包表記

   ・{キーの式: 値の式 for 変数 in 反復可能体}

dic = {x: x**3 for x in (1, 3, 6)}
print(dic, type(dic))

Result

{1: 1, 3: 27, 6: 216} <class 'dict'>

 

》補足

・初期化

l = []         # ( 空リスト )
t = ()         # ( 空タプル )
d = {}         # ( 空ディクショナリ )
s = set()      # ( 空集合 )
print(type(l), type(t), type(d), type(s))

Result

<class 'list'> <class 'tuple'> <class 'dict'> <class 'set'>


第7章 モジュール

・インポート

 ・インタープリターや別のファイルを利用できる仕組みをインポートという

 ・インポートされるファイルをモジュールという

 ・モジュールをインポート 

  ・import モジュール名

 ・インポートしたモジュールの関数を実行 

  ・モジュール名.関数名()

 ・関数のみをインポート 

  ・from モジュール名 import 関数名

 ・名前をすべてインポート 

  ・from モジュール import * 

  ・すべての名前(関数や変数)が使える

  ・アンダースコアー「_」で始まる名前はインポートされない

  ・モジュールの名前はインポートされない

  ・モジュールに__all__という変数のリストが存在した場合は、そのリスト内の名前だけインポートされる 

  ・as を使ったインポート

  ・as でモジュールや関数を別名でインポートできる

  ・モジュールの別名でインポート

   ・import モジュール名 as モジュールの別名

  ・関数の別名でインポート。モジュール名はインポートされない

   ・from モジュール名 import 関数名 as 関数の別名

  ・関数の別名はモジュール名と同じ名前でも大丈夫

 

・メインモジュールか否かの判定

 ・メインモジュールとはスクリプトとして実行された.pyファイルのこと

 ・__name__はモジュールの属性であり、モジュール名が自動で代入される

 ・メインモジュールで実行された場合、"__main__"が代入される

 ・インポートされたモジュールはメインモジュールではない

if __name__ == "_main__" :
    print("Main Module") 

 

・__init__.py(ダンダーイニット)

 ・ディレクトリに__init__.pyというファイルを配置すると、ディレクトリ名のモジュールとしてインポートされる

 ・このような構成をパッケージという

 ・パッケージにすることで別の.pyファイルをまとめて扱える。この別のファイルをパッケージのサブモジュールという

 ・__init__.pyではサブモジュールをインポートできない

 ・__init__.pyからサブモジュールをインポートするには、通常、相対インポートで記述する

 ・相対インポート

  ・同じ階層から別サブモジュールをインポート     from .  import 別サブモジュール

  ・同じ階層から別サブモジュールの名前をインポート  from .別サブモジュール import 名前

  ・1つ上の階層から別サブモジュールをインポート   from .. import 別サブモジュール

  ・1つ上の階層の別サブモジュールの名前をインポート from ..別サブモジュール import 名前

bookcard/
    __init__.py
    dump.py
    load/
        __init__.py
        core.py

 

》補足

・dir関数

 ・dir() はそのオブジェクトの属性(変数や関数、オブジェクトなど)をリストで返してくれる

import math
print(dir(math))

Result

['__doc__', '__loader__', '__name__', ... , 'tau', 'trunc', 'ulp']

 


第8章 ファイル入出力

・open関数のモード

 ・open("ファイル名", mode="モード")

 ・r: 読み込み専用(デフォルト) r+:読み書き両用 w:新規書き込み a:追加書き込み b:バイナリモード

 ・wb:バイナリモードで新規書き込み ab:バイナリモードで追加書き込み rb:バイナリモードで読み込み

 

 

・ファイルを閉じる処理

 ・open関数の返り値であるファイルオブジェクトは、ファイルの処理後に閉じる必要がある

 ・閉じるにはcloseメソッドを使用する

 ・with文を使うことでこの閉じる処理が自動で行われる。この処理は例外が発生した時にも行われる

  ・with open("ファイル名") as ファイルオブジェクト変数:

 ・1つのファイルオブジェクトでwithを使っても、別のファイルオブジェクトが閉じられることはない

 ・プログラムが終了する際に全てのファイルオブジェクトが閉じられる。このためすぐ終了する場合は閉じる処理を省略できる

with open("weekly.csv") as fp:
    s = fp.read()
print(s)

 

 ・ファイルを読み込み

 ・ファイルを1行ずつ読み込む for s in fp:

 ・ファイルオブジェクトはリストと同様な反復可能体の1つなのでfor文で繰り返すことができる

 ・以下も1行ずつ処理できるがファイル内容をすべて読み込んでから行毎に分けるため上記に比べメモリを消費するので避けるべき

  ・for s in fp.readlines(): または for s in list(fp):

 ・fp.read() が処理するのは「ファイル全体の文字列」になる。そのため  for s in fp.read(): と記述すると1行ずつではなく

  「1文字ずつ」の処理になる

fp = open("weekly.csv")
for s in fp:
    print(s)

 

・ファイルの書き込み

 ・ファイルにデータを書き込む fp.write(文字列)

 

・JSON形式の書き込み

 ・オブジェクトをJSON形式で書き込む   json.dump(data, fp) 

 ・キーワード引数を使用することも可能   json.dump(fp=fp, obj=data)

 ・json.dumps() はオブジェクトからJSON形式の文字列を返す関数。ファイルオブジェクトを引数指定できない

 ・json.dumps() で書き込むには fp.write(json.dumps(data)) と記述する

 

・JSON形式を読み込む

 ・JSON形式のデータを読み込む json.load(fp) または json.loads(fp.read())

 

 

》補足

・シリアライズとは

 Pythonのオブジェクトや文字列をJSON形式に変換すること

 

・デシリアライスとは

 JSON形式のデータをPythonのオブジェクトや文字列に変換すること

Chapter11 ファイルとディレクトリへのアクセス

・pathlibモジュール - ファイルパス操作を直観的に行う

 ・pathlibモジュールが提供するクラスは、以下の2つに分けられる

  ・I/Oの伴わない機能を提供する純粋パス(pure path)

  ・I/Oの伴う機能を提供する具象パス(concrete path)

 

 ・クラス構成

クラス名 解説 基底クラス
pathlib.PurePath 純粋パスクラスの基底クラス なし
pathlib.PurePosixPath 非Windows向けの純粋パスクラス PurePath
pathlib.PureWindowsPath Windows向けの純粋パスクラス PurePath
pathlib.Path 具象パスクラスの基底クラス PurePath
pathlib.PosixPath 非Windows向けの具象パスクラス PurePosixPath, Path
pathlib.WindowsPath Windows向けの具象パスクラス PureWindowsPath, Path
# Windowsの場合
from pathlib import Path

p = Path()          # ( 基底クラスをインスタンス化する
p                   # WindowsPath('.')  ( モジュール側でプラットフォームを認識してWindowsPathのインスタンスを返す )

 基本的にはPathクラスを使用すれば問題ない。具象パスクラスであるPathは純粋パスクラスであるPurePathのサブクラスなので、

 純粋パスクラスと具象パスクラスの両方の機能が使用できる

 

 ・純粋パスを扱う ─ PurePath

  ・純粋パスの機能はファイルシステムにアクセスしないため、OS上に存在しないファイルパスを扱える

# 以下のコードはPathオブジェクトでも同様に動作する。また、Windows環境で実行した場合、インスタンスはPureWindowsPathとなる

# PurePathオブジェクトを生成する
from pathlib import PurePath, Path

PurePath('spam.txt')                             # PurePosixPath('spam.txt')
PurePath('spam', 'ham', 'eggs.txt')              # PurePosixPath('spam/ham/eggs.txt')  ( 複数のパスを連結 )
PurePath('spam/ham', 'eggs.txt')                 # PurePosixPath('spam/ham/eggs.txt')
PurePath(Path('spam'), Path('ham'), 'eggs.txt')  # PurePosixPath('spam/ham/eggs.txt')  ( 引数にPathオブジェクトを指定 ) 
PurePath()                                       # PurePosixPath('.')  ( 引数を指定しない場合はカレントディレクトリ )
# PurePathやPathでは、除算演算子(/)でパスを追加できる
from pathlib import Path

p = Path('/usr') 
p                      # PosixPath('/usr') 
p / 'bin' / 'python3'  # PosixPath('/usr/bin/python3') 

q = Path('hosts') 
'/usr' / q             # PosixPath('/usr/hosts')

 

  ・PurePathクラスのインスタンス変数

プロパティ名 解説 戻り値
PurePath.parts パスの各要素のタプルを返す tuple
PurePath.drive ドライブを表す文字列を返す。 存在しない場合は空文字列を返す str
PurePath.root ルートを表す文字列を返す str
PurePath.anchor ドライブとルートを結合した文字列を返す str
PurePath.parents 上位パスにアクセスできるシーケンスを返す Path オブジェクトのシーケンス
PurePath.parent バスの直接の上位パスを返す Path オブジェクト
PurePath.name パス要素の末尾を表す文字列を返す str
PurePath.suffix 末尾の要素の拡張子を返す str
PurePath.suffixes 末尾の要素の拡張子をリストで返す list
PurePath.stem 末尾の要素から拡張子を除いたものを返す str
from pathlib import PurePath, PureWindowsPath 

p = PurePath('/spam/ham/egg.tar.gz') 
p.parts                  # ('/', 'spam', 'ham', 'egg.tar.gz')  ( 各要素を取得 )

wp = PureWindowsPath('c:/Program Files/spam/ham.exe') 
wp.parts                 # ('c:\\', 'Program Files', 'spam', 'ham.exe') 

p.drive                  # '' ( ドライブを取得 ) 
wp.drive                 # 'c:'
 
p.root                   # '/' ( ルートを取得 )  
wp.root                  # '\\'

wp.anchor                # 'c:\\' ( ドライブとルートを結合した文字列を取得 )

for parent in p.parents: # 上位のパスのシーケンスを取得
    parent
# PurePosixPath('/spam/ham')
# PurePosixPath('/spam')
# PurePosixPath('/') 

p.parent                 # PurePosixPath('/spam/ham') ( 直接の上位のパスを取得 )
p.name                   # 'egg.tar.gz' ( 末尾の要素を取得 ) 
p.suffix                 # '.gz' 拡張子を取得  
p.suffixes               # ['.tar', '.gz'] ( 拡張子のリストを取得 )
p.stem                   # 'egg.tar' ( 末尾の要素から拡張子を除いたものを取得 )

 

  ・PurePathクラスのメソッド

メソッド名 解説 戻り値
PurePath.is_absolute() パスが絶対パスである場合に True を返す bool
PurePath.is_relative_to(*other) other のパスに対して相対であればTrue を返す bool
PurePath.match(pattern) glob形式の引数 pattern と一致する場合に True を返す bool
PurePath.with_name (name) パスのname部分を、引数で指定したものに変更したパスを返す Path オブジェクト
PurePath.with_stem(stem)

パスのstem部分を、引数で指定したものに変更したパスを返す

strem部分とは、パス要素の末尾から拡張子を除いたもの

Path オブジェクト
PurePath.with_suffix(suffix) パスの拡張子を引数で指定したものに変更したパスを返す Path オブジェクト
from pathlib import PurePath

p1 = PurePath('/spam/ham/eggs.txt') 
p2 = PurePath('eggs.txt') 
p1.is_absolute()            # True  ( 絶対パスか  )
p2.is_absolute()            # False 
p1.is_relative_to('/spam')  # True  (指定したパスに対して相対か )
p1.is_relative_to('/ham')   # False ( 指定したパスに対して相対か )
p1.match('*.txt')           # True  ( パターンに一致するか )  
p1.with_name('hoge.txt')    # PurePosixPath('/spam/ham/hoge.txt') ( nameを変更(eggs.txt→hoge.txt))  
p1.with_stem('fuga')        # PurePosixPath('/spam/ham/fuga.txt') ( stemを変更(eggs→fuga))
p1.with_suffix('.py')       # PurePosixPath('/spam/ham/eggs.py')  ( 拡張子を変更(.txt→.py)) 
p1.with_suffix('')          # PurePosixPath('/spam/ham/eggs')     ( 拡張子を削除 )

 

 ・具象パスを扱う ─ Path

  ・Pathクラスは具象パスの基底クラス

  ・インスタンス化すると、Windowsの場合はWindowsPathクラス、非Windowsの場合はPosixPathクラスのインスタンスオブジェクトとなる

  ・具象パスの機能はファイルシステムにアクセスするため、基本的にOS上に操作対象のファイルパスが存在する必要がある

メソッド名 解説 戻り値
Path.cwd ( ) 現在のディレクトリを表すパスオブジェクトを返す。クラスメソッド パスオブジェクト
Path.home() ユーザーのホームディレクトリを表すパスオブジェクトを返す。クラスメソッド パスオブジェクト
Path.stat() ファイルの各種情報を返す os.stat_resultオブジェクト
Path.chmod(mode) パスのパーミッションを変更する None
Path.exists() パスが存在する場合に True を返す bool
Path.glob(pattern) パスが指すディレクトリ以下のpattern に一致するファイルやディレクトリの一覧を、パスオブジェクトとして返すジェネレーターを返す ジェネレーター
Path.is_dir() パスがディレクトリである場合に True を返す bool
Path.is_file() パスがファイルである場合に True を返す bool
Path.iterdir() パス以下に存在するファイルやディレクトリの一覧を、パスオブジェクトとして返すジェネレーター を返す ジェネレーター
Path.mkdir(mode=0o777, parents=False, exist_ok=False) パスを新しいディレクトリとして作成する None
Path.open(mode='r', buffering=-1, encoding=None, errors=None, newline=None) 組み込み関数の open() と同様にファイルを開く ファイルオブジェクト
Path.read_text(encoding=None, errors=None) ファイルの内容を文字列として返す 文字列
Path.rename (target) パスの名前を変更する。 引数 target には文字列かほかのパスオブジェクトを指定する None
Path.resolve(strict=False) パスを絶対パスにし、 シンボリックリンクを解決する パスオブジェクト
Path.rmdir ( ) パスが指すディレクトリを削除する。ディレクトリは空の必要がある None
Path.touch(mode=00666, exist_ok=True) バスにファイルが存在しなければファイルを作成する。 ファイルが存在すれば更新日時を現在日時に変更する None
Path.unlink(missing_ok=False) パスのファイルを削除する None
Path.write_text(data, encoding=None, errors = None) ファイルに data を書き込む。 書き込んだ文字数を返す int
from pathlib import Path 

Path.cwd()                           # PosixPath('/Users/takanori/spam/ham')  ( 現在のディレクトリ ) 
Path.home()                          # PosixPath('/Users/takanori')  ( ホームディレクトリ ) 

p = Path('spam.txt' )p.exists()                           # True  ( 存在を確認 ) 
p.stat().st_mode                     # 33188  ( 状態を取得 )
p.chmod(0o600)                       # ( パーミッションを変更 )
p.stat().st_mode                     # 33152 
p.is_file()                          # True  ( ファイルかどうか )
with p.open(encoding='utf-8') as f:  # スパムスパムスパム  ( ファイルを開く )
    print(f.read())
p.write_text('ハムハムハム', encoding='utf-8')  # 6  ( ファイルに書き込み )
p.read_text(encoding='utf-8')        # 'ハムハムハム'  ( ファイルから読み込み )  
p.unlink()                           # ( ファイルを削除 )
p.exists()                           # False 
p.touch()                            # ファイルを作成 
p.resolve()                          # PosixPath('/Users/takanori/spam/ham/spam.txt')  ( 絶対パスを取得 ) 

  ・パスが指すディレクトリ内のファイルやディレクトリを探索する場合はPath.glob()やPath.iterdir()メソッドが便利

  ・Path.iterdir()とPath.glob()はどちらもジェネレーターを返すので、「for f in p.iterdir()」のように、forループでパスオブジェクトを1つずつ

   取り出して処理できる

# ディレクトリ構造の例
./a.py 
./b.py 
./datas 
./datas/c.txt 
./datas/d.txt 
./readme.txt

from pathlib import Path 

p = Path()                  # ( 現在のディレクトリのパスオブジェクトを取得 )
p.iterdir()                 # ( iterdir()はジェネレーターを返す )
# <generator object Path.iterdir at 0x7f9f300f7740>
sorted(p.iterdir())         # ( ディレクトリ直下の全オブジェクトを返す )
# [PosixPath('a.py'), PosixPath('b.py'), PosixPath('datas'), PosixPath('readme.txt')] 
list(p.glob('*.txt'))       # ( *.txtというファイルを返す )
# [PosixPath('readme.txt')] 
sorted(p.glob('**/*.txt'))  # ( ディレクトリを再帰的にたどって*.txtというファイルを返す )
# [PosixPath('datas/c.txt'), PosixPath('datas/d.txt'), PosixPath('readme.txt')]

 

・tempfileモジュール - 一時的なファイルやディレクトリを生成する

 ・tempfileモジュールは、作成したユーザーのみ読み書き可能なパーミッション設定が行われる、作成時に競合しないなど、可能な限り

  安全な方法で実装される

 ・紹介する4つの呼び出し可能オブジェクトは、すべてコンテキストマネージャーとして使用できる。そのため、with文と併せて使用すると、

  自動的に後処理をしてくれる

呼び出し可能オブジェクト 解説 データの書き出し先 ファイル名
TemporaryFile() ファイル名のない一時ファイルを作成する ディスク上 なし
NamedTemporaryFile() ファイル名がある一時ファイルを作成する ディスク上 あり
SpooledTemporaryFile() 一定サイズまではデータはメモリ上で処理され、それを超えるとディスクに書き出される一時ファイルを作成する メモリ上→ディスク上 なし
TemporaryDirectory() 一時ディレクトリを作成する

 

 ・一時ファイルを作成する

  ・TemporaryFile()で作成された一時ファイルは、ファイルシステム上に名前を持ったファイルとして作成される保証がない

  ・TemporaryFile()およびSpooledTemporaryFile()で作成された一時ファイルはファイルパスを値とする属性を持たないため、

   exists()メソッドでのファイルの存在を確認できない

import tempfile

# withブロックを抜けるとファイルを閉じて削除される with tempfile.TemporaryFile() as tmpf: tmpf.write(b'test test test\n') # 15 ( tmpf.write()の戻り値 ) tmpf.seek(0) # 0 ( tmpf.seek()の戻り値。オフセットを先頭へ移動 ) tmpf.read() # b'test test test\n' ( tmpf.read()の戻り値 ) tmpf = tempfile.TemporaryFile() tmpf.write(b'Hello tempfile\n') # 14 tmpf.seek(0) # 0 tmpf.read() # b'Hello tempfile\n' tmpf.close() # ファイルを閉じると削除される
  ・ファイルシステム上に名前が付いたファイルを作成したい場合はNamedTemporaryFile()を使用する。引数はTemporaryFileと同様
# 名前を持った一時ファイルの作成 
import tempfile 
from pathlib import Path 

tmpf = tempfile.NamedTemporaryFile() 

tmpf.name # /var/folders/lp/xhvsj17d1yb2cgfkc7cwhcsw0000gn/T/tmplff0pcgw ( ファイル名を確認 ) p = Path(tmpf.name) p.exists() # True ( ファイルの存在を確認 ) tmpf.close()

 

 ・一時ディレクトリを作成する

   ・TemporaryDirectoryもTemporaryFileと同様にコンテキストマネージャーとして機能し、ブロックを抜けるとディレクトリとその

   ディレクトリのなかのファイルがすべて削除される

import tempfile 
from pathlib import Path
 
with tempfile.TemporaryDirectory() as tmpdirname:
    tmpdirname              # '/var/folders/lp/xhvsj17d1yb2cgfkc7cwhcsw0000gn/T/tmpc87au9hb' ( ディレクトリ名を取得 )
    p = Path(tmpdirname)
    p.exists()              # ディレクトリの存在を確認
    p2 = p / 'hoge.txt'
    p2.touch()              # True ( ディレクトリの下にファイルを作成 )
    p2.exists()             # True ( ファイルの存在を確認 )

p.exists()                  # False ( withブロックを抜けるとディレクトリとファイルが削除される )
p2.exists()                 # False
# コンテキストマネージャーとして使わずに明示的にディレクトリを削除したい場合
tmpdir = tempfile.TemporaryDirectory()
tmpdir.cleanup() 

 

・shutilモジュール(シューティル) - 高レベルなファイル操作を行う

 ・ファイルをコピーする

  ・copyfile()はファイルのデータのみをコピーする

  ・copy()はファイルのデータとパーミッションをコピーするが、ファイルの作成時間や変更時間などのメタデータはコピーしない

  ・メタデータをコピーしたい場合はcopy2()を利用する

  ・copy()の内部ではcopyfile()とcopymode()が、copy2()の内部ではcopyfile()とcopystat()が呼ばれている

関数名 解説 戻り値
copyfile(src, dst, *, follow_symlinks=True) ファイル srcをファイルまたはディレクトリを指すdstにコピーする str
copy(src, dst, *, follow_symlinks=True) copyfile() と同様にファイルをコピーし、 ファイルのパーミッションもコピーする str
copy2 (src, dst, *, follow_symlinks=True) copy() と同等の機能に加えて、すべてのメタデータを保持しようとする str
copymode(src, dst,*, follow_symlinks=True) パーミッションをsrcからdstにコピーする None
copystat(src, dst, *, follow_symlinks=True)

パーミッション、 最終アクセス時間、 最終変更時間やその他のファイル情報を

srcからdst にコピーする

None

 

  ・使う関数によってファイルのパーミッション、更新日時などのメタデータがコピーされている場合と、いない場合がある 

import shutil

shutil.copyfile('a.txt', 'b.txt')  # 'b.txt' 
shutil.copy('a.txt', 'c.txt')      # 'c.txt' 
shutil.copy2('a.txt', 'd.txt')     # 'd.txt'

% ls -l
-rw------- 1 takanori staff 4 Feb 14 16:16 a.txt
-rw-r--r-- 1 takanori staff 4 Feb 14 16:17 b.txt  # ( ファイルのデータのみコピー )
-rw------- 1 takanori staff 4 Feb 14 16:17 c.txt  # ( パーミッションもコピー )
-rw------- 1 takanori staff 4 Feb 14 16:16 d.txt  # ( メタデータもコピー )

   ・ファイルをディレクトリにコピーする

# copy()とcopy2()のdstにはディレクトリを指定できますが、copyfile()ではディレクトリは指定できない
import shutil

shutil.copy('a.txt', 'e/')     # 'e/a.txt' 
shutil.copy2('a.txt', 'e/')    # 'e/a.txt' 
shutil.copyfile('a.txt', 'e/') # IsADirectoryError'

 

 ・再帰的にディレクトリやファイルを操作する

関数名 解説 戻り値
rmtree(path, ignore_errors=False, onerror=None) pathで指定したディレクトリ以下のファイルをすべて削除する None
move(src, dst, copy_function=copy2) srcディレクトリ以下のファイルを再帰的にdstに移動する。コピー時に使用する関数を指定できる (デフォルトはcopy2) str

 

   ・あるディレクトリ以下のファイルやディレクトリをまるごとコピーしたい場合

import shutil

ignore = shutil.ignore_patterns('*.pyc', '*.swp')  # 拡張子が.pycと.swpを除外対象にする 
ignore                                             # ignore(path, names)という呼び出し可能オブジェクト 
# <function ignore_patterns.<locals>._ignore_patterns at 0x7fe7d821aa60>
shutil.copytree('./from', './to', ignore=ignore)   # fromからtoに再帰的にコピー

Chapter13 特定のデータフォーマットを扱う

・csvモジュール - CSVファイルを扱う

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

関数名 解説 戻り値
csv.reader(csvfile, dialect='excel', **fmtparams) CSVファイルの各行のデータを反復処理するような readerオブジェクトを返す reader オブジェクト
csv.writer(csvfile, dialect='excel', **fmtparams)

CSVファイルのデータを、引数で指定した区切り方法で書き込むための writerオブジェクトを返す

lineterminator=’\n’で、改行方法を指定できる

writer オブジェクト

 

  ・CSVファイルの読み込み

import csv

# UTF-8エンコーディングで作成されたcsvファイルを開く 
with open('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']


# TSVファイルの読み込み
with open('sample.tsv', mode='r') as f:
    reader = csv.reader(f, delimiter='\t')
    for row in reader:
        print(row)
# ['都道府県', '人口密度(人/km2)']
# ['東京', '#6335#']
# ['埼玉県', '#1922#']


# 引用符を「#」に指定して読み込む
with open('sample.tsv', mode='r') as f:
    reader = csv.reader(f, delimiter='\t', quotechar='#')
    for row in reader:
        print(row)
# ['都道府県', '人口密度(人/km2)']
# ['東京', '6335']   ( 「#」は引用符としてみなされ、要素の値には含まれない )
# ['埼玉県', '1922']

   ・CSVファイルの書き込み

メソッド名 解説
writerow(row) データを書式化し、 writerのファイルオブジェクトに書き込む。row には文字列か数値のイテラブルを指定する
writerows(rows) 複数行を書き込むために、上述のwriterow() メソッド同様に row オブジェクトのイテラブルのすべての要素を指定する
import csv

with open('sample.csv', mode='r', encoding='utf-8') as read_file:
    reader = csv.reader(read_file)
    next(reader)                                                # ( ヘッダー行を飛ばす )

    with open('result.tsv', newline='', mode='w', encoding='utf-8') as write_file:
        writer = csv.writer(write_file, delimiter='\t')
        writer.writerow(['都道府県', '人口密度(人/km2)'])     # ( ヘッダー行を書き込み )
        
        for row in reader:
            population_density = float(row[2]) / float(row[3])  # ( 人口と面積の数値を利用して人口密度を求める )
            writer.writerow([row[1], int(population_density)])  # ( ファイルの書き込み )
# 都道府県 人口密度(人/km2) 
# 東京都 6335 
# 神奈川県 3807 
# 千葉県 1202

  ・辞書データを用いたCSVファイルの読み込みと書き込み

メソッド 解説
DictWriter.writeheader() DictWriterコンストラクターで指定されたfieldnames を使用してヘッダー 行に書き込む
# 読み込んだファイルの1行目を辞書のキーとする辞書型としてデータが取得
import csv

with open('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'}
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)  # ( データの一括書き込み )
# 出力結果
# 都道府県,人口密度(人/km2) # 東京都,6335 # 神奈川県,3807

   ・csvモジュールのSniffer(スニッファー)クラスは、CSVファイルのデータ形式を推測するためのクラス。このクラスを使用すると、

   CSVファイルもTSVファイルも1つのコードで自動判別して読み込めるので便利

メソッド 解説
sniff(sample, delimiters=None) sampleで受け取ったデータを解析し、推測したDialect サブクラスを返す。delimiters引数はオプションで、可能性のあるデリミターがあれ ば指定する
has_header(sample) ヘッダーの有無を判定する
import csv 

with open('result.tsv', newline='') as f:
    dialect = csv.Sniffer().sniff(f.read(1024))  # ( サンプルとして1024バイト分のデータをsniff()に渡す )
    f.seek(0)                                    # ( ファイルオブジェクトの位置を先頭に戻す )
    reader = csv.reader(f, dialect)              # ( 推測されたdialectを使用して読み込む )
    for row in reader:
        print(row)
# ['都道府県', '人口密度(人/km2)']
#(省略)

 

・jsonモジュール - JSONを扱う

 ・Pythonのリストと辞書が組み合わされたデータをJSONエンコードする

# JSONエンコード(エンコードを行うと、Pythonの各種データ型がJSON形式の文字列に変換)
import json 
data = [{'id': 123, 'entities': {'url': 'python.org', 'hashtags': ['#python','#pythonjp']}}]
print(json.dumps(data, indent=2))  # ( indentオプションでインデントのスペースの数を指定できる )
[
  {
    "id": 123,
    "entities": {
      "url": "python.org",
      "hashtags": [
        "#python",
        "#pythonjp"
      ]
    }
  }
]
print(json.dumps(data, indent=2, sort_keys=True)) # ( sort_keys=Trueを指定すると、keyでソートされた結果が出力される ) [ { "entities": { "hashtags": [ "#python", "#pythonjp" ], "url": "python.org" }, "id": 123 } ]

  ・JSONデコード

from decimal import Decimal

json_str = '["ham", 1, "egg", 1.0, {"a":false, "b" :null}]' 
json.loads(json_str)                       # ['ham', 1, 'egg', 1.0, {'a': False, 'b': None}] 

# parse_floatを指定すると、JSONの浮動小数点数文字列が指定された型に変換される 
json.loads(json_str, parse_float=Decimal)  # ['ham', 1, 'egg', Decimal('1.0'), {'a': False, 'b': None}] 

# parse_intを指定すると、JSONの整数文字列が指定された型に変換される 
json.loads(json_str, parse_int=float)      # ['ham', 1.0, 'egg', 1.0, {'a': False, 'b': None}]

  ・文字列を扱う関数は、loads()とdumps()。ファイルオブジェクトを扱う関数はload()とdump()

関数名 解説 戻り値
dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw) obj で指定した Python のオブジェクトをJSONに変換し、ファイルオブジェクトに書き込む。 引数fp以外の使い方は dumps() と同等 なし
load(fp, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw) 引数 fpで指定したファイルオブジェクトから読み込んだJSON 文字列をPython オブジェクトに変換する。引数 fp以外の使い方はloads() と 同等 Python オブジェクト
with open('./sample.json', mode='r') as f:
    json_string = json.load(f)
    
    json_string  # 内容の確認 
    # [{'id': 123, 'entities': {'url': 'www.python.org', 'hashtags': ['#python','#pythonjp']}}]
    
    json_string[0]['entities']['hashtags'].append('#pyhack')
    with open('dump.json', mode='w') as f:
        json.dump(json_string, f, indent=2)

# 上記の実行の結果(dump.json) 
[
  {
    "id": 123,
    "entities": {
      "url": "python.org",
      "hashtags": [
        "#python",
        "#pythonjp",
        "#pyhack"
      ]
    }
  }
]

 

 ・通常curlコマンドでJSONを取得すると1行表示となり見にくいが、json.toolを使用することで、見やすく表示できる

$ curl --request GET --url 'https://weatherbit-v1-mashape.p.rapidapi.com/alert?lat=35.69&lon=13.7' | python -m json.tool
{ 
  "alerts": [], 
  "city_name": "Tokyo", 
  "country_code": "JP", 
  "lat": 35.69, 
  "lon": 139.7, 
  "state_code": "40", 
  "timezone": "Asia/Tokyo"
}

第9章 例外

・構文エラー

 ・pythonの文法として正しくないコードを実行すると構文エラー(SyntaxError)になる

 

・例外

 ・コードが文法として正しい場合でも実行時にエラーが発生することがある。これを例外(exception)という

 ・例外が起きたことを検知して例外発生時の動作を実装するには try - except文 を使う

 ・try節の中には通常の処理を書き、except節ではtry節で発生しうる例外に対する処理を書く

 ・except節で複数の例外を処理するには、()の中に処理したい例外をすべて列挙する

 ・except節の処理が不要なときは下記のように記述する

try:
    
except StopIteration:
    pass

  ・raise文を使うことで任意の例外を発生させられる

try:
    raise ValueError("ValueErrorです")
except ValueError as error:
    print(error)

Result

ValueErrorです

 

・クリーンアップ動作

 ・try文にfinally節を追加することでクリーンアップ動作を定義できる

 ・例外発生の有無に関わらず実行する処理

def divide(a, b):
    try:
        answer = a / b
        return answer
    except ZeroDivisionError:
        print("ゼロ除算が行われました")
    except TypeError:
        print("引数の型が不正です")
    finally:
        print("--finally節の処理--") # ( finallyにreturn文が定義されてないので返り値はNone )

answer = divide(100, "0")
print(f"結果:{answer}") 

Result

引数の型が不正です

--finally節の処理--

結果:None

 

》補足

・except 例外名 as 変数名

 ・変数に例外オブジェクトを格納して使用できる

 ・例外オブジェクトはエラーメッセージなどが格納されており、エラーの内容を確認できる

try:
    a = int("word")
except ValueError as error:
    print(error)

Result

invalid literal for int() with base 10: 'word'

 

・raiseを除いた全パターン

try:
    print(5 ** 2)
    print((5 ** 2) / 0)
except(ValueError) :
    pass                           # ( この例外に対して何もしない )
except(ZeroDivisionError) :
    print('D')
except Exception as e:
    print('e.__class__.__name__')  # ( その他のエラー )
else:
    print('F')                     # ( 例外が発生しなかった )
finally:
    print('G')                     # ( 例外の有無に関係なく実行 )

Result

25

D

G

 

・エラーメッセージ

 ・AttributeError  :存在しないデータの名前を参照したとき  例 リスト名.add(3) リストにaddメソッドは存在しない

 ・TypeError    :意図しないデータ型が与えられたとき   例 リスト名 += 3 リスト以外を代入しようとした。100 / "10"

 ・ValueError      :int型に変換できない             例 int("word")

 ・NameError     :存在しない関数などを参照したとき    例 count(リスト名) countは組み込み関数に存在しない

 ・IndexError      :要素が存在しないインデックスを指定したとき

 ・SyntaxError    :構文に問題がある場合に発生するエラー

 ・ModuleNotFoundError:指定されたモジュールがない

 ・KeyError     :ディクショナリに存在しないキーを参照しようとしたとき

 ・KeyboardInterrupt :「Ctrl + C」を押したとき

 

》補足

・パーサ(構文解釈器)は違反のある行を表示し、最初にエラーが検知された点に小さな矢印が付けられる。エラーは矢印より前のトークンが原因である

Chapter3 Python言語使用

・例外処理

 ・基底クラスで補足

  ・BaseExceptionを親としたExceptionクラスがあり、Exceptionを継承した形で、子・孫クラスの例外が存在している

  ・exceptに捕捉したい例外の基底クラスを指定しても、その子・孫クラスの例外を捕捉できる

  ・基底クラスで補足しても渡される例外オブジェクトは変わらない

 ・独自の例外を定義

  ・Exceptionクラスから派生したクラスであればraiseキーワードを使用して例外を発生できる

class MyError(Exception):
    pass

raise MyError

  ・複数の例外を送出するようなモジュールを作成する際は、そのモジュールで定義されている例外の基底クラスを作成するのが一般的

 ・一般的にtry文で囲む範囲は狭いほがいい

 ・except節で例外の種類を指定しないとエラー原因が特定できない、プログラムを停止できなくなるなどの弊害がしょうじるので非推奨


第10章 クラスとオブジェクトの操作

・クラス定義

 ・クラスを構成する要素には、クラス変数、インスタンス変数、メソッドがある

 ・クラス変数(①)

  ・クラスで保持する変数。そのクラスのすべてのインスタンスで共有される

  ・クラス変数はクラスの直下に定義

  ・宣言は「変数名 = 値」の書式で記述

  ・アクセスは「クラス名.変数名」の書式で記述

 ・インスタンス変数(②、③)

  ・インスタンス毎に固有の変数

  ・インスタンスを初期化するための特殊メソッドである__init__メソッドの中で定義する

  ・__init__メソッドには、selfという引数を与える

  ・インスタンス変数は「self.変数名 = 値」の書式で定義

 ・メソッド(④)

  ・クラスに定義された関数

  ・メソッドの定義の仕方は関数と同じだが、第1引数にselfを与える

  ・メソッド内でクラス変数を参照する場合は、self. を付ける必要がある

class Duck:
    # クラス変数familyの定義
    family = "Anatidae"                   # ①

    # 特殊メソッド__init__の定義
    def __init__(self):                   # ②
        # インスタンス変数birdsongの定義
        self.birdsong = "quack"           # ③
    
    # show_familyメソッドの定義
    def show_family(self):                # ④
        return f"Ducks belong to the family {self.family}."

》補足

・self

 ・そのクラスのインスタンスを表す

 ・selfはメソッドの呼び出し元で引数に渡す必要はなく、pythonが自動的に呼び出されたメソッドの第1引数としてインスタンス

  を渡してくれる

 

・インスタンス化

 ・変数名 = クラス() の書式で行う duck = Duck()

 ・__init__メソッドを定義することで、インスタンス化時の処理を記述できる

 ・このメソッドの第1引数であるselfは、そのクラスのインスタンスを表す特殊な引数

 ・第2引数以降は、呼び出し元から渡された引数をそのまま受け取れる

 ・メソッド内にインスタンス変数と同名のローカル変数がある場合、それらは別の変数として扱われる

 ・メソッド内でインスタンス変数を参照・更新する場合、変数名の先頭に self. を付ける

class Duck:
    def __init__(self, birdsong):
        # インスタンス変数birdsongの定義
        # 引数birdsongの値で初期化する
        self.birdsong = birdsong
    
    def sing(self):
        return self.birdsong

duck = Duck("quack")

 

・メソッド

 ・同一クラスに定義された他のメソッドを呼び出す際は、メソッド名の先頭に self. を付ける

class Duck:
    def __init__(self):
        self.birdsong = "quack"
    
    def change_birdsong(self, birdsong):
        self.birdsong = birdsong

    def show_birdsong(self):
        print(self.birdsong)
        self.change_birdsong("ga-ga-")
        print(self.birdsong)

duck = Duck()
duck.show_birdsong()

Result

quack

ga-ga-

 

・派生クラス

 ・class 派生クラス(基底クラス):

 ・pythonでは定義済みのクラスを基にして、別のクラスを作成できる。これをクラスの継承と呼ぶ

 ・継承元となるクラスを基底クラス、継承先になるクラスを派生クラスと呼ぶ

 ・派生クラスは基底クラスの、クラス変数、インスタンス変数、、メソッドを受け継ぐ

 ・あるクラスを継承するときに、基底クラスと同名のクラス変数、インスタンス変数、メソッドを定義する場合、それらは上書きされる

 ・super().メソッド() で継承した基底クラスのメソッドを呼び出せる。その際引数にselfは不要

# 基底クラス
class
Person():
def __init__(self, name, age): self.name = name self.age = age def say_name(self): print("私の名前は" + self.name + "です。年齢は" + str(self.age) + "歳です。") # 派生クラス class JapanesePerson(Person): def __init__(self, name, age): super().__init__(name, age) # ( 基底クラスのメソッドの呼び出し ) def say_hello(self): print("こんにちは") yamada = JapanesePerson("山田", 20) yamada.say_name() yamada.say_hello()

Result

私の名前は山田です。年齢は20歳です。

こんにちは

 

・オブジェクトの判定

 ・type関数は、引数に指定したオブジェクトの型を返す

 ・isinstance関数は、第1引数に判定したいオブジェクトを指定、第2引数に型や基底クラスを指定する

 ・issubclass関数は、クラスBがクラスAから派生しているかを判定する issubclass(クラスB, クラスA)

print(isinstance(duck, Duck))

Result

True

Chapter4 Pythonのクラス

・メソッドには以下の3種類が存在する

 ・インスタンスメソッド

  ・一般にメソッドというとインスタンスメソッドのことをいう

  ・クラス内で動作するように、第1引数にselfが渡され、インスタンス化されたクラスの属性やメソッドを使うことができる

 ・クラスメソッド

  ・クラスオブジェクトを暗黙的に第1引数にとる、特別なメソッド。

  ・@classmethod デコレータはメソッドの処理をクラス全体に関連付ける機能を追加

  ・引数 cls は、そのクラス自身を指す変数。インスタンスメソッドにおいて self

  ・クラスメソッドではクラス自身を指す変数 cls を用いて cls.クラス変数名 でクラス変数にアクセスする

  ・外部情報に依存したインスタンスを生成する場合などの特殊なインスタンス化に使用

class クラス名:
    @classmethod
    def クラスメソッド名(cls, クラスメソッド引数):
        # クラスメソッドの処理をここに記述する

 ・静的メソッド

  ・インスタンス化せずに使うことを前提にしたメソッドを定義

  ・@staticmethodデコレーターをメソッドに使うことで定義

 

・サンプル

# class_sample.pyモジュール
class User:
    user_type = None

    def __init__(self, name, age, address):
        self.name = name
        self.age = age
        self.address = address

    def __repr__(self):
        return f""

    def __len__(self):
        return len(self.name)

    def __eq__(self, other):  # ( otherは比較対象のインスタンス )
        return self.age == other.age 

    def increment_age(self):
        self.age += 1

    @property
    def start_name(self):
        if len(self.name) > 0:
            return self.name[0]
        else:
            return ""

・特殊メソッド

 ・特殊メソッドは、メソッド名の前後にアンダースコア(_)を2個付けたもの

 ・コンストラクターメソッド __init__() も、特殊メソッドの1つ

 ・特殊メソッドでは、関数が実行されたときの挙動や演算子の挙動を決めることができる

 

 ・関数による挙動

  ・__repr__() :オブジェクトをprint()関数で出力したときの文字列表現を変更できる

from class_sample import User

user = User("寺田学", 35, "東京都台東区")
print(user)  # ( __repr__()でオブジェクトIDとnameを返す )

   ・__len__()  :組み込み関数len()は引数に与えたオブジェクトの__len__()メソッドを呼び出す

from class_sample import User

user = User("寺田学", 35, "東京都台東区")
len(user)  # ( __len__()でnameの桁数を返す )

 

 ・演算子による挙動

  ・__add__()       :足し算で使う演算子(+)の挙動には、__add__()という特殊メソッドが呼び出される

  ・__eq__()         :==では__eq__()メソッドが呼び出される

from class_sample import User

user_1 = User("寺田学", 35, "東京都台東区")
user_2 = User("鈴木たかのり", 30, "東京都千代田区")
user_1 == user_2  # _( _eq__()で年齢を比較 )

 ・主な特殊メソッド

__init__ コンストラクター(初期化時に使われる)
__call__ 呼び出し可能化(関数のようにインスタンスを呼び出せるようにする)
__repr__ 文字列表現
__str__ 文字列型へお変換
__len__ 要素数の取得(len()関数で呼ばれる)
__lt__ 小なり比較  他(__le__、__eq__、__ne__、__gt__、__ge__)
__add__ 加算演算子 他(__sub__、__mul__、__truediv__)

 

・プロパティ化

 ・インスタンスメソッドをプロパティ化するとカッコを付けずに呼び出せる

# 通常のインスタンスメソッドの呼び出しにはカッコを付ける
user.start_name()

# 関数宣言に@propertyデコレーターを使いプロパティ化したメソッドは、カッコがいらない
user.start_name

 

・クラスメソッドの具体的な使い方

 ・datetimeにはクラスメソッドで宣言されているnow()メソッドが存在する

 ・インスタンスのメソッドを呼び出すのとは違い、datetime.now() とクラスオブジェクトに対し直接メソッド実行できる

from datetime import datetime

dt_now = datetime.now()
dt_now  # datetime.datetime(2025, 5, 23, 16, 10, 5, 596305)

 

・多重継承

class Custom(Base1, Base2):
    pass

 ・多重継承は、継承関係の把握が難しくなり、複雑で混乱を招く場合がありる

 ・このCustomクラスの属性の参照やメソッドの呼び出しをしたとき、Base1の属性やメソッドを最初に調べ、Base1の親クラスの
  属性やメソッドを調べたあとに、Base2の属性やメソッドを調べる

 ・Pythonにおいては、多重継承の継承順位をMRO(Method Resolution Order)という仕組みで、C3アルゴリズムを用いて探索する

 

・dataclass

 ・クラスデコレーターを用いてクラスを宣言し、クラス属性を宣言する

 ・宣言の際に型ヒント(型アノテーション)を用いる

 ・例として、サンプル:class_sample.pyのUserクラスをdataclassとして宣言

from dataclasses import dataclass

@dataclass  # クラスデコレーターでdataclassを宣言
class User:
    name: str                       # ( クラス変数を宣言、型ヒントを宣言 )
    age: int
    address: str

user = User("manabu", 50, "Chiba")  # ( クラスをインスタンス化 )
user                                # User(name='manabu', age=50, address='Chiba')  ( インスタンス化したクラスを確認  )

 ・detaclass宣言で、コンストラクターメソッドである__init__()や、特殊メソッドである__repr__()などが自動的に定義される

 ・detaclassを使うことで以下の定義を省略でき、データを管理するクラスをシンプルにすることが出来る

class User:
    def __init__(self, name, age, address):
        self.name = name
        self.age = age
        self.address = address

    def __repr__(self):
        return f"User(name='{self.name}', age={self.age}, address='{self.address}')"

 ・dataclassデコレーターに引数を与えて挙動を変えることができる。frozen=Trueで属性の変更ができなくなる

  ここではfrozen引数を設定し、データ変更ができないdataclassを宣言

@dataclass(frozen=True)

 ・コンストラクターの任意引数

  ・デフォルト値を設定する場合は、デフォルト値を持たない属性よりも下に宣言する必要がある

@dataclass
class User:
    name: str
    age: int
    address: str
    active: bool = False  # ( デフォルト値を設定 )

user = User("takanori", 40, "Tokyo")   # ( 任意引数をインスタンス時に設定しない )
user                                   # User(name='takanori', age=40, address='Tokyo', active=False)

 ・データ変換

  ・dataclassで宣言したクラスは、辞書やタプルに変換する仕組みが提供されている

@dataclass
class User:
    name: str
    age: int
    address: str

from dataclasses import asdict, astuple

user = User("manabu", 50, "Chiba")
user           # User(name='manabu', age=50, address='Chiba')

asdict(user)   # ( 辞書型に変換 )
{'name': 'manabu', 'age': 50, 'address': 'Chiba'}

astuple(user)  # ( タプル型に変換 )
('manabu', 50, 'Chiba')

 

・オブジェクト関連関数

 ・id(object) オブジェクトの識別値であるidを整数で返す

 ・type(object) オブジェクトの種類を返す

 ・help(object) オブジェクトのヘルプを表示する。docstringがあるとhelp()関数で確認できる


第11章 標準ライブラリ

・OSモジュール

 ・os.getcwd() でカレントディレクトリを取得

 ・os.chdir("..") でカレントディレクトリから上の階層へ移動

 

・globモジュール

 ・glob.glob("*.ipynb") でカレントディレクトリ下のパターンにマッチするファイルの一覧を取得する

 

・sysモジュール

 ・python check.py 1 2 をコマンドライン実行すると sys.argvはコマンドライン情報を取得し[’check.py', '1', '2'] が返ってくる

 

・argparseモジュール

 ・argparseモジュールのArgumentParse() を使ってもコマンドライン引数を取得できる

 ・parserという名前でパーサ(構文解釈l器)のオブジェクトを作成(①)

 ・add_argument() で引数の情報を追加。ここでは2種類(--head と body)(②)

  コマンド実行時、"--head"は「--head=値」、"body", nargs="+"は1個以上の「任意形式」の引数の指定

  ハイフン付は任意引数。引数名が1文字の場合はハイフンは1つでよい(-a)。ハイフンがないものは必須引数

 ・parser.parse_args() で引数の情報を取得できる(③)

 ・Resultのように2種類の引数の値を確認できる(④)

import argparse

parser = argparse.ArgumentParser()      # ①
parser.add_argument("--head")           # ②
parser.add_argument("body", nargs="+")  # ②
args = parser.parse_args()              # ③
print(args)                             # ④

Result

python> python parse.py --head=1 2 3

Namespace(head='1', body=['2', '3'])              

 

・mathモジュール

 ・数学に関する定数や関数が定義されている

 ・log() は対数を求める関数。log(値, 底) は返り値をnとした場合、底のn乗が値になる。log(16, 2)は、2の4乗が16なので

  返り値は「4.0」を返す

 ・pi は円周率を参照する定数(3.141592653589793

 ・tau(タウ) は「円周と半径の比」(2π = 6.283185307179586)

 

・randomモジュール

 ・乱数を生成するための関数を定義

 ・random.choice(range(10)) は0から9のうち1つをランダムに選ぶ関数。連続して実行した場合、出力が重複する可能性がある

 ・random.random()

  ・random.random()    0以上1未満のランダムな値(少数)を返す

  ・random.random() - 1   -1以上0未満のランダムな値(少数)を返す

  ・random.random() * 2   0以上2未満のランダムな値(少数)を返す

  ・random.random() * 2 -1   -1以上1未満のランダムな値(少数)を返す

 ・random.sample(l, n) 第1引数のリストからランダムに第2引数の取得数を選択してリストで返す。出力が重複する可能性がある

 ・random.randrange(1, 6, 2) はrange(1, 6, 2) の要素からランダムに選ばれた要素を返す

 

・statisticsモジュール

 ・数理統計に用いる関数が含まれている

 ・statistics.mean()   データの平均値

 ・statistics.median()   データの中央値

 ・statistics.variance()  データの不偏分散

 ・不偏分散の計算式 平均との差の2乗の和を「データ数 - 1」で割った値

 ・[ -1, -1, -1, -1, 4 ] の場合

  ・平均値: 0

  ・中央値:-1

  ・不平分散:( 1**2+1**2+1**2+1**2+4**2 ) / (5 - 1) = 5

 

・urllib.requestモジュール

 ・urlopen() は引数で指定したURLのWebサイトからさまざまな情報を取得できる

 ・urlopen() は対象のデータをバイナリモードで取得するのでdecode() でバイナリデータを文字列に変換が必要

from urllib.request import urlopen
with urlopen("https://www.yahoo.co.jp/") as rs:
        s = rs.read().decode() 

 

・datetimeモジュール

 ・日付と時刻を扱うさまざまな関数が定義されている

 ・datetime() で指定した日付のdatetimeオブジェクトを作成

 ・strftime() で指定された表示形式で出力される

from datetime import datetime
dt = datetime(2000, 12, 31)
print(f"{type(dt)}\n{dt}\n{dt.strftime("%Y-%m-%d")}")

Result

<class 'datetime.datetime'>

2000-12-31 00:00:00

2000-12-31

 

 ・timedeltaオブジェクトは2つの日付や時間の間の差を表せる機能を定義。daysメソッドで日数部分を取得できる

 ・日付の引き算はdatetimeオブジェクト同士、あるいはdateオブジェクト同士で可能

from datetime import date
dt1 = date(2001, 1, 1)
dt2 = date(2002, 2, 2)
print(type(dt1))
diff = dt2 - dt1
print(f"{type(diff)}\n{diff}\n{diff.days}")

Result

<class 'datetime.date'>

<class 'datetime.timedelta'>

397 days, 0:00:00

397

 

・unittestモジュール

 ・単体テストを実行するのに使用する

 ・一般的に、unittestによる単体テストではテスト対象のモジュールとは別に、テスト実行側の.pyファイルを用意する必要がる

 ・コマンドラインから「python -m unittest」のように実行すると、対象の関数やメソッドのテスト結果を確認できる

# test.pyの処理内容

import unittest
import mod

class TestSample(unittest.TestCase):
    def test_it(self):
        actual = mod.calc(2, 3)              # ( テスト対象の実行結果 )
        expected = 5                         # ( 期待する結果 )
        self.assertEqual(actual, expected)   # ( 結果が同じことを確認 )

 

・リストやディレクトリなどを整形

 ・pprintモジュール

  ・pprint() は1行が80文字を超えると要素ごとに改行する

  ・widthで改行を適宜変更可能

import pprint
lines = [f"sample test string {i:04}" for i in range(3)]
pprint.pprint(lines)

Result

['sample test string 0000',

'sample test string 0001',

'sample test string 0002']

 

 ・textwrapモジュール

  ・widthで指定した幅に収まるよう整形する

  ・pprintのように角括弧を付けず出力される

import textwrap
text = [f"{i} sheep jumped  fence." for i in range(1, 4)]
print(textwrap.fill(", ".join(text), width=24))

Result

1 sheep jumped fence.,

2 sheep jumped fence.,

3 sheep jumped fence.

 

・reモジュール 参考 Pythonの正規表現モジュールreの使い方 、Pythonにおける正規表現の使い方

 ・正規表現を扱う関数

  ・sub() はマッチした部分を他の文字列に置換する

  ・compile() は正規表現パターン文字列をコンパイルして正規表現パターンオブジェクトを作成する

  ・search() は文字列すべてが検索対象で、先頭にない文字列にもマッチする

  ・match() は文字列の先頭位置からだけマッチするどうか調べる

 

 ・正規表現パターン

  ・[a-z]+ は小文字のアルファベットが1文字以上繰り返される文字列にマッチ

  ・[efg] はe,f,g のいづれかの1文字とマッチ

  ・a.{3}e はa...eと同じ。{n]は直前のパターンをn回繰り返し

  ・メタ文字(特別な意味を持つ文字)は\でエスケープが必要

  ・\1, \2, … は'\\1'のようにエスケープが必要だが、raw文字列を使うとr'\'ですむ

 

 ・メタ文字

  ・「.」 改行以外の任意の1文字

  ・「*」 直前のパターンを0回以上繰り返し

  ・「+」 直前のパターンを1回以上繰り返し

  ・「?」 直前のパターンを0回または1回繰り返し

 

 ・特殊シーケンス

  ・\d 全ての数字 [0-9]

  ・\D 全ての数字以外 [^0-9]

  ・\w 全ての英数字とアンダーバー [a-zA-Z0-9_]

  ・\W 全ての英数字とアンダーバー以外 [^a-zA-Z0-9_]

  ・\l 半角英小文字 [a-z]

  ・\L 半角英小文字以外 [^a-z]

  ・\u 半角英大文字 [A-Z]

  ・\U 半角英大文字以外 [^A-Z]

 

 ・フラグ設定

  ・re.IGNORECASE を指定すると大文字小文字を区別せずマッチする

 

import re
s = "tic tac tac toe"
print(re.sub(r"([a-z]+) \1", r"\1", s))  # tic tac toe
import re
prog = re.compile('Kus(a|u)n(a|o|k)g?i(saya|ro)?', re.IGNORECASE)  # ( Patternオブジェクトを返す )
ret = prog.search('KUSANAGI')        # ok KUSANAGI  ( マッチするとMatchオブジェクトを消す )
ret = prog.search('Kusanagi saya')   # ok Kusanagi
ret = prog.search('Kusunoki')        # TypeError 
ret = prog.search('KUSANOGI')        # ok KUSANOGI
ret = prog.search('Kusanoiro')       # ok Kusanoiro
print(ret[0])

 

・loggingモジュール

 ・loggerにはsetLevelがあり、logger毎に扱うログのレベルを設定可能

 ・レベルの高い順:CRITICAL、ERROR、WARNING、INFO、DEBUG

 ・loggerのsetLevel:WARNING

 ・各loggerにはhandlerがありhandlerごとにログの出力先の設定や、handler自体にもsetLevelを設定可能

import logging
logger = logging.getLogger()
logger.info("infomation message")
logger.error("error message")

Result

error message

 

・collectionsモジュール

 ・Counterオブジェクト - リスト要素の集計をする

from collections import Counter
a = [1, 2, 3, 1, 2, 1, 4, 5, 2]
print(Counter(a)) 

Result

Counter({1: 3, 2: 3, 3: 1, 4: 1, 5: 1})

 

・Processing(プロセッシング)モジュール

 ・簡単に画面に絵を出したりマウスの操作で絵を動かしたりできる

 

・smtplibモジュール

 ・任意のインターネット上のホストにメールを送ることができる

 

》補足

・loggingモジュール

 ・ログ出力を行うには、getLogger 関数を用いてログを出力するためのロガーオブジェクトを作成する

 ・ロガーオブジェクトを作成する際は、getLogger 関数の引数にロガーの識別名を指定することができる

  識別名は省略可だが、マジック変数 __name__ を指定することが一般的

 ・取得したロガーオブジェクトは、出力するログレベルに応じてメソッドを使い分け

 ・ERROR の際に使用するメソッドとして error と exception の2つが、error() メソッドは単にエラーメッセージを記録、

  exception() メソッドは例外処理の中で呼び出すことでエラーに関する情報も自動でログに含められる

 ・ログ出力の設定はファイル出力やファイルローテーション、ログのフィルタリングなど詳細な設定が可能

 ・詳細な設定が必要ない場合は basicConfig 関数を使うことで簡単にログの設定を行うことができる

import logging

# level        :ログレベルの指定
# %(asctime)s  :ログを出力した日時を指定
# %(levelname) :ログレベルを指定
# -5s          :-:左寄せ、5:最小幅、s:文字列
# %(message)   :ログのメッセージを指定
# filename     :ログを出力するファイル名を指定。レベルによって出力先を変えることも出来る
#                ファイル名を指定しない場合は sys.stderr に出力される
logging.basicConfig(
    level=logging.INFO, 
    format='[%(asctime)s][%(levelname)-5s] %(message)s',
    filename="log.txt"
)

logging.info("メソッドの動作確認開始")
try:
    logging.info("exception メソッドの動作確認")
    result = 1 / 0
except ZeroDivisionError:
    logging.exception("exception メソッドによるログ出力")  # このログ出力では詳細なエラー情報が出力される
    
logging.info("メソッドの動作確認終了")

標準ライブラリ+

Chapter5 型ヒント

・operatorモジュール

 ・attrgetter クラスやdataclassのソート

 ・itemgetter リストや辞書などのソート

from operator import itemgetter, attrgetter
from datetime import date
from dataclasses import dataclass

# attrgetter
@dataclass 
class User:
        name: str
        gold: int

users = [
        User("yusha", 300),
        User("sorho", 200),
        User("maho", 100)
]
print(f"attrgetter: {sorted(users, key=attrgetter("gold"))}")  # ( 所持金でソート )

# itemgetter
data = [(1, 40, 200), (3, 10, 100), (2, 20, 300), (1, 30, 300)]
print(f"itemgetter: {sorted(data, key=itemgetter(2))}")

Result

attrgetter: [User(name='maho', gold=100), User(name='sorho', gold=200), User(name='yusha', gold=300)]

itemgetter: [(3, 10, 100), (1, 40, 200), (2, 20, 300), (1, 30, 300)]

Chapter6 テキストの処理

・reモジュール

 ・reモジュールの定数(フラグ)

A、ASCII \w、\sなどのマッチング処理でUnicodeではなくASCII文字のみを使用する
I、IGNORECASE(イグノアケース) 大文字小文字を区別せずにマッチする
M、MULTILINE 複数行のテキストを指定したときに^と$が各行の先頭と末尾にマッチする
S、DOTALL ドット「.」 が改行文字も含めてマッチする
re.search('\w', 'あいうえおABC')
# <re.Match object; span=(0, 1), match='あ'> re.search('\w', 'あいうえおABC', flags=re.A) # ( ASCII文字のみにマッチ )
# <re.Match object; span=(5, 6), match='A'> re.search('[abc]+', 'ABC') # ( マッチなし ) re.search('[abc]+', 'ABC', re.I) # ( 大文字小文字を無視 )
# <re.Match object; span=(0, 3), match='ABC'> re.search('a.c', 'a\nc') # ( マッチなし ) re.search('a.c', 'a\nc', re.S) # ( .が改行文字にマッチ )
# <re.Match object; span=(0, 3), match='a\nc'> re.search('a.c', 'A\nC', re.I | re.S) # ( 複数のフラグを指定 )
# <re.Match object; span=(0, 3), match='A\nC'>

 

 ・正規表現オブジェクト(compile()関数に正規表現のパターンを指定して作成)で使用できる主なメソッド

search(string[, pos[, endpos]]) 指定した文字列が正規表現にマッチするかを返す。pos、endposはマッチ処理の対象となる文字列の位置を指定する マッチオブジェクトまたはNone
match(string[, pos[, endpos]]) 指定した文字列が正規表現にマッチするかを返す。search()と異なり、先頭からマッチするかを確認する マッチオブジェクトまたはNone
fullmatch(string[, pos[, endpos]]) 指定した文字列全体が正規表現にマッチするかを返す マッチオブジェクトまたはNone
split(string, maxsplit=0) 指定した文字列を正規表現パターンにマッチした文字列で分割する。maxsplitに分割の最大数を指定する

文字列のlist

sub(repl, string, count=0) 指定した文字列のなかで正規表現パターンにマッチした文字列をreplに置き換える。countは変換する上限を指定する str
findall(string[, pos[, endpos]]) 指定した文字列中の正規表現にマッチした文字列すべてをリストで返す 文字列のlist
finditer(string[, pos[, endpos]]) 指定した文字列中の正規表現にマッチしたマッチオブジェクトをイテレーターで返す イテレーター
# 以下は、正規表現パターンにマッチしたマッチオブジェクトを取得するメソッドのサンプルコード

import
re regex = re.compile('[a-n]+') # ( a-nの範囲の英小文字にマッチする正規表現オブジェクト ) regex.search('python') # ( hの文字にマッチ ) <re.Match object; span=(3, 4), match='h'> regex.match('python') # ( 先頭がマッチしないのでNoneを返す ) regex.fullmatch('eggs') # ( 文字列全体とマッチするか ) regex.fullmatch('egg') <re.Match object; span=(0, 3), match='egg'>
# 以下は正規表現パターンにマッチする文字列での分割と、置換を実行するサンプルコード

import re
regex2 = re.compile('[-+()]')       # ( 電話番号に使われる記号のパターンを定義 )

regex2.split('080-1234-5678')       # ( 記号のパターンで分割 )
# ['080', '1234', '5678']

regex2.split('(080)1234-5678')
# ['', '080', '1234', '5678']

regex2.split('+81-80-1234-5678')
# ['', '81', '80', '1234', '5678']

regex2.sub('', '+81-80-1234-5678')  # ( 記号パターンを削除する )
# '818012345678'
# 以下は、正規表現パターンにマッチする文字列をリスト形式とイテレーターで取得するサンプルコード

import re
regex3 = re.compile('\d+')               # ( 1文字以上の数字の正規表現オブジェクト )

regex3.findall('080-1234-5678')          # ( 文字列中の数字文字列を抜き出す )
# ['080', '1234', '5678']

i = regex3.finditer('+81-80-1234-5678')  # ( 文字列中の数字文字列を返すイテレーター )
for m in i:  マッチオブジェクトを取り出す
    print(m)
# <re.Match object; span=(1, 3), match='81'>
# <re.Match object; span=(4, 6), match='80'>
# <re.Match object; span=(7, 11), match='1234'>
# <re.Match object; span=(12, 16), match='5678'>

 

 ・マッチオブジェクト

  ・マッチオブジェクトは、re.match()やre.search()などで正規表現にマッチした文字列に関する情報を保持するオブジェクト

 ・サブグループ

  ・正規表現の中で()で囲んだ部分はサブグループとなり、カッコの中にあるパターンにマッチした文字列のみを取り出すことができる

# マッチオブジェクトに対してgroup()メソッドまたは[]でインデックスを指定すると、サブグループを取得できる

import
re m = re.match(r'(\d+)-(\d+)-(\d+)', '080-1234-5678') # 電話番号の正規表現 m.group(0) # マッチした文字列全体を取得 # '080-1234-5678' m.group(1) # サブグループを指定 # '080' m.group(1, 2, 3) # 複数のサブグループを指定 # ('080', '1234', '5678') m[0] # マッチした文字列全体を取得 # '080-1234-5678' m[1] # サブグループを指定 # '080'

 

 ・名前付きのグループを指定するには、正規表現を「(?P<name>...)」という形式で記述

# 名前付きサブグループを指定するサンプルコード 
import re m2 = re.match(r'(?P\w+) (?P\w+)', '鈴木 たかのり') # ( 姓名を取得する正規表現 ) m2.group('last') # ( サブグループ名を指定 ) # '鈴木' m2.group('first') # 'たかのり' m2.group('last', 'first') # ('鈴木', 'たかのり') m2['first'] # ( []でもサブグループ名での指定が可能 ) # 'たかのり' m2.group(1) # ( 数値での指定も可能 ) # '鈴木' m2[2] # 'たかのり'

 

 ・マッチオブジェクトの主なメソッド

groups(default=None) パターンにマッチしたサブグループの文字列をタプルで返す。defaultはマッチする文字列が存在しない場合に返す値を指定する tuple
groupdict(default=None) パターンにマッチしたサブグループを辞書で返す。defaultはマッチする文字列が存在しない場合に返す値を指定する dict
expand(template) テンプレート文字列に対して\1または\g<name>の形式でサブグループを指定すると、マッチした文字列に置き換えられる str
# マッチオブジェクトのメソッドのサンプルコード 

import re
m = re.match(r'(\w+) ?(\w+)? (\w+)', 'Guido van Rossum')
# ?(\w+)?の意味
#  ? :直前のスペースにマッチするかどうか判定
#  (\w+) :1つ以上の英数字またはアンダースコアーにマッチするグループを定義
#  ? :前のグループがマッチするかどうか判定
m.groups() # ('Guido', 'van', 'Rossum') # ( マッチしたサブグループを取得 ) m = re.match(r'(\w+) ?(\w+)? (\w+)', 'Takanori Suzuki') m.groups() # ( ミドルネームがないのでNoneになる ) # ('Takanori', None, 'Suzuki') m.groups('van') # ( デフォルト値を指定 ) # ('Takanori', 'van', 'Suzuki') m = re.match(r'(?P\w+) (?P\w+)', '鈴木 たかのり') m.groupdict() # ( マッチした文字列を辞書形式で取得 ) # {'last': '鈴木', 'first': 'たかのり'} m.expand(r'名前: \1\2') # ( テンプレート文字列を使用 ) # '名前: 鈴木たかのり' m.expand(r'名字(\g) 名前(\g)') # ( テンプレート文字列にサブグループ名を指定 ) # '名字(鈴木) 名前(たかのり)'

 

・unicodedataモジュール

 ・Unicodeデータベースにアクセスする機能を提供

 ・Unicodeデータベースにはアルファベット、漢字、世界中の文字、絵文字など多種多様な文字の情報が含まれている

 ・unicodedataモジュールの関数

lookup(name) 指定された名前に対応する文字を返す。存在しない場合はKeyErrorを返す str
name(chr[, default]) 文字chrに対応する名前を返す。名前が定義されていない場合はValueErrorを返す。defaultが指定してある場合はその値を返す str
normalize(form, unistr)

form:正規化の形式。NFC/NFKC/NFD/NFKD、 unistr:正規化する対象の文字列

NFKCを指定すると日本語はすべて全角に、英数字はすべて半角に変換。一般的にはNFKCを使用する。入力された文字列を正規化して検索対象の文字列と比較することで、半角全角などの表記揺れを無視した検索が実現できる

正規化された文字列
import unicodedata

unicodedata.lookup('Latin Small Letter a')             # ( 半角小文字のaを取得 )
# 'a'
unicodedata.lookup('BEER MUG')                         # (ビールジョッキの絵文字を取得 )
'🍺for chr in ('A', 'A', '1', 'い', 'カ', '㌧', '', ''):  # ( いろいろな文字の名前を取得 )
    unicodedata.name(chr)
# 'LATIN CAPITAL LETTER A'
# 'FULLWIDTH LATIN CAPITAL LETTER A'
# 'DIGIT ONE'
# 'HIRAGANA LETTER I'
# 'HALFWIDTH KATAKANA LETTER KA'
# 'SQUARE TON'
# 'SNOWMAN'
# 'SUSHI'

unicodedata.normalize('NFKC', 'アアAA!!@@') # ( NFKCで正規化 ) # 'アアAA!!@@'

Chapter8 日付と時刻の処理

・datetimeモジュール

 ・date - 日付を扱う

 ・time - 時刻を扱う

 ・datetime - 日時を扱う

 ・timedelta - 2つの日時の差を扱う

 

・dateオブジェクト  - 日付を扱う

today() 今日の日付のdateオブジェクトを生成する datetime.date
weekday() 月曜日を0、日曜日を6として曜日を返す int
isoweekday() 月曜日を1、日曜日を7として曜日を返す int
isoformat() ISO8601形式YYYY-MM-DDで表した日付文字列を返す str
fromisoformat(date_string) ISO8601形式YYYY-MM-DDで表した文字列をdateオブジェクトに変換する datetime.date
strftime(format) 指定したフォーマットに従って日付文字列を返す str
from datetime import date

ganjitsu = date(2021, 1, 1)

ganjitsu                            # datetime.date(2021, 1, 1)
ganjitsu.year, ganjitsu.month, ganjitsu.day  # (2021, 1, 1)  ( 年月日を取得 )
ganjitsu.weekday()                  # 4  ( 2021年の元日の曜日は金曜日 )
ganjitsu.isoformat()                # '2021-01-01'
date.fromisoformat('2021-01-01')    # datetime.date(2021, 1, 1)
str(ganjitsu)  # '2021-01-01'
ganjitsu.strftime('%Y/%m/%d')       # '2021/01/01'         ( 日付をスラッシュ区切りの文字列に変換 )
ganjitsu.strftime('%Y %b %d (%a)')  # '2021 Jan 01 (Fri)'  ( 日付を月、曜日の文字列付きで変換 )

date.today()                        # datetime.date(2021, 2, 14)
today = date.today()
f'今日は{today:%Y年%m月%d日}'       # '今日は2021年02月14日'    ( f-stringでも日付を文字列に変換できる )

 

・timeオブジェクト - 時刻を扱う

 ・日本の時間は、ロンドン(協定世界時 UTC)から9時間進んでいる時間(UTC+9時間)として表示される

 ・UTC (Coordinated Universal Time) とは、現在の世界の標準時間の基準として使用されている時刻系(協定世界時とも呼ばれいる)

 ・タイムゾーン (Time Zone) は、同じ標準時を使用する地域全体を指す。 日本は標準時が1つ設定されており、北海道に居ても沖縄に
  居ても日本の1つのタイムゾーンを共有する

 ・ISO 8601は、国際標準化機構(ISO)が定めた日付と時刻の表記に関する国際規格

isoformat(timespec='auto') ISO8601形式 HH:MM:SS.ffffff、またはマイクロ秒が0の場合はHH:MM:SSの文字列を返す str
fromisoformat(time_string) ISO8601形式 HH:MM:SS.ffffffで指定した文字列をtimeオブジェクトに変換する datetime.time
strftime(format) 指定したフォーマットに従って時刻の文字列を返す str
tzname() タイムゾーンの名前の文字列を返す str
from datetime import time
time() # datetime.time(0, 0) time(16, 12, 25) # datetime.time(16, 12, 25) time(minute=10) # datetime.time(0, 10) time(second=10) # datetime.time(0, 0, 10) time(microsecond=10) # datetime.time(0, 0, 0, 10)
now = time(16, 12, 25) now.hour, now.minute, now.second, now.microsecond # (16, 12, 25, 0) now.isoformat() # '16:12:25'
time.fromisoformat('16:12:25') # datetime.time(16, 12, 25) time.fromisoformat('16:12:25.000384') # datetime.time(16, 12, 25, 384) time.fromisoformat('16:12:25+04:00') # datetime.time(16, 12, 25, tzinfo=datetime.timezone(datetime.timedelta(seconds=… now.strftime('%H:%M') # '16:12' str(now) # '16:12:25'

 ・timeモジュールはエポック(epoch)という基準となる時間からの経過時間を扱う

 ・ エポック (epoch) は時刻の起点のこと。エポックは通常、1970年1月1日0時0分0秒

 ・時刻を取得する

gmtime([secs]) UTCの現在時刻を返す。secsを指定した場合は指定されたエポックからの経過時間で表現された時刻を返す time.struct_time
localtime([secs]) ローカルの現在時刻を返す。secsを指定した場合は指定されたエポックからの経過時間で表現された時刻を返す time.struct_time
time() エポックからの秒数を浮動小数点で返す flot
import time

time.gmtime()     # ( tm_mday:日の値、tm_yday:年の中での日数、tm_isdst:夏時間でないか )
# time.struct_time(tm_year=2021, tm_mon=2, tm_mday=14, tm_hour=13, tm_min=23, tm_sec=37, tm_wday=6, tm_yday=45, tm_isdst=0)
time.localtime()  # ( 日本標準時(JST)はUTCの9時間後 )
# time.struct_time(tm_year=2021, tm_mon=2, tm_mday=14, tm_hour=22, tm_min=23, tm_sec=59, tm_wday=6, tm_yday=45, tm_isdst=0)
time.strftime('%Y-%m-%d', time.localtime())  # '2021-02-14'
time.time()                                  # 1613309062.411699

 ・sleep()関数を使用すると、現在のスレッドを指定した秒数一時停止できる

import time
time.time()
time.sleep(0.5)  # ( 0.5秒一時停止する )

 

・datetimeオブジェクト - 日時を扱う

today() デフォルトのタイムゾーンの現在日時を返すクラスメソッド。todayという名前だが時刻の値も設定する datetime.datetime
now(tz=None) デフォルトのタイムゾーンの現在日時を返すクラスメソッド。tzにzoneinfo.Zonfinfoオブジェクトを渡せばタイムゾーンを変更できる datetime.datetime
utcnow()

UTC(協定世界時)の現在日時を返すクラスメソッド

datetime.datetime
date() 同じ年月日のdateオブジェクトを返す datetime.date
time() 同じ時分秒のtimeオブジェクトを返す datetime.date
isoformat(sep='T', timespec='auto') ISO8601形式 YYYY-MM-DDTHH:MM:SS.ffffff、またはマイクロ秒が0の場合はYYYY-MM-DDTHH:MM:SSの文字列を返す str
fromisoformat(date_string) ISO8601形式 YYYY-MM-DDTHH:MM:SS.ffffffで文字列をdatetimeオブジェクトに変換する datetime.datetime
strftime(format) 指定したフォーマットに従って日時の文字列を返す str
strptime(date_string, format) 指定したフォーマットに従って文字列をdatetimeオブジェクトに変換する datetime.datetime
tzname() タイムゾーンの名前の文字列を返す str
from datetime import datetime

now = datetime.now()  # ( 現在日時を取得 )
now.date()            # datetime.date(2021, 2, 14)        ( dateを取得 )
now.time()            # datetime.time(17, 26, 8, 585404)  ( timeを取得 )
now.isoformat()       # '2021-02-14T17:26:08.585404'      ( ISO 8601形式の文字列を取得 )

# ISO 8601形式で文字列をdatetimeオブジェクトに変換
datetime.fromisoformat('2021-02-14')                  # datetime.datetime(2021, 2, 14, 0, 0)
datetime.fromisoformat('2021-02-14T00:05:23')         # datetime.datetime(2021, 2, 14, 0, 5, 23)
datetime.fromisoformat('2021-02-14T17:26:08.585404')  # datetime.datetime(2021, 2, 14, 17, 26, 8, 585404)

now.strftime('%Y/%m/%d')                     # '2021/02/14'  ( フォーマットを指定して文字列を取得 )
datetime.strptime('2021/02/14', '%Y/%m/%d')  # datetime.datetime(2021, 2, 14, 0, 0)  ( 文字列をdatetimeオブジェクトに変換 )

from zoneinfo import ZoneInfo
datetime(2021, 5, 24, 22, 50, 0, 0, tzinfo=ZoneInfo('Asia/Tokyo')) # ( tzinfoにタイムゾーンを指定 )
# datetime.datetime(2021, 5, 24, 22, 50, tzinfo=zoneinfo.ZoneInfo(key='Asia/Tokyo'))

 

・timedeltaオブジェクト - 日時の差を扱う

from datetime import date, datetime, time, timedelta

today = date.today()            # ( 今日の日付を取得 )
today                           # datetime.date(2021, 2, 14)
newyearsday = date(2022, 1, 1)  # ( 2022年1月1日 )
newyearsday - today             # datetime.timedelta(days=321)  ( 今日から来年の1月1日までの日数 )
week = timedelta(days = 7)      # ( 1週間のtimedeltaを生成 )
today + week                    # datetime.date(2021, 2, 21)    ( 1週間後の日付を取得 )
today + week * 2                # datetime.date(2021, 2, 28)    ( 2週間後の日付を取得 )
today - week                    # datetime.date(2021, 2, 7)     ( 1週間前の日付を取得 )

datetime(2021, 5, 24, 21, 0, 0, 0) - datetime(2021, 5, 24, 20, 0, 0, 0)  # ( 日時の差分を取得 )
# datetime.timedelta(seconds=3600)

 

・zoneinfoモジュール - IANA(アイアナ)タイムゾーンデータベース

 ・IANAタイムゾーンデータベースとは

  ・Internet Assigned Numbers Authority(IANA)が管理

  ・世界各地のタイムゾーン情報を収めたデータベースのこと

from zoneinfo import ZoneInfo

ASIA_TOKYO = ZoneInfo('Asia/Tokyo')
ASIA_TOKYO  # zoneinfo.ZoneInfo(key='Asia/Tokyo')

from datetime import datetime

dt = datetime(2021, 2, 23, 10, tzinfo=ASIA_TOKYO)  # ( 日本時刻で2021年2月23日10:00のdatetimeオブジェクトを作成 )
dt  
# datetime.datetime(2021, 2, 23, 10, 0, tzinfo=zoneinfo.ZoneInfo(key='Asia/Tokyo'))

dt.astimezone(ZoneInfo('America/Los_Angeles'))     # ( 日本時刻2021年2月23日10:00をアメリカのロサンゼルスの日時に変換 )
# datetime.datetime(2021, 2, 22, 17, 0, tzinfo=zoneinfo.ZoneInfo(key='America/Los_Angeles'))

 

Chapter9 データ型とアルゴリズム

・collectionsモジュール - さまざまなコンテナー型を扱う

 ・Counter   :データの件数をカウントする

 ・defaultdict  :デフォルト値を持った辞書 

 ・OrderedDict  :データの挿入順を維持する辞書

 ・namedtuple  :名前付きフィールドを持つタプル

 

・Counterオブジェクト

 ・辞書を拡張してオブジェクトを数える機能に特化したクラス

 ・辞書のキーが要素となり、値にその要素の数を保存される

 ・辞書では存在しないキーを指定して値を取得しようとするとKeyErrorが発生するがCounterでは0を返す

from collections import Counter

c = Counter('Good morning.')  # ( 文字列を渡す )
c                             # Counter({'o': 3,'n': 2,'G': 1,'d': 1,' ': 1,'m': 1,'r': 1,'i': 1,'g': 1,'.': 1})
c['a']                        # 0  ( 存在しないキーを指定した場合は0を返す

  ・Counterオブジェクトのメソッド

elements() 要素のキーを、値の数だけ繰り返すイテレーターを返す。カウンターが負の数の場合は無視される キー値のイテレーター
most_common([n]) 値が大きい順にキーと値のペアを返す。nに整数値を指定すると、最大n件の要素を返す リスト
subtract([iterable-or-mapping]) 要素からイテラブルまたはマッピングオブジェクトの値を減算する None
update([iterable-or-mapping]) 要素にイテラブルまたはマッピングオブジェクトの値を加算する None
from collections import Counter

c = Counter(a=4, b=1, c=-2, d=2)
c                        # Counter({'a': 4, 'd': 2, 'b': 1, 'c': -2})
list(c.elements())       # ['a', 'a', 'a', 'a', 'b', 'd', 'd']  ( カウンターの数分キーを返す )
c.most_common(2)         # [('a', 4), ('d', 2)]  ( 値が大きい順に2件取得する )

c2 = Counter(a=1, b=3, e=1)
c.subtract(c2)           # ( cからc2を減算する )
c                        # Counter({'a': 3, 'd': 2, 'e': -1, 'b': -2, 'c': -2})
c.update(c2)             # ( cにc2を加算する )
c                        # Counter({'a': 4, 'd': 2, 'b': 1, 'e': 0, 'c': -2})

c1 = Counter(a=2, b=1)
c2 = Counter(a=1, b=3)
c1 + c2                  # ( 値同士が加算される )

 

・defaultdictオブジェクト

 ・defaultdictは辞書から派生したクラスですが、存在しないキーを参照したときにデフォルト値が返される

d = {'spam':100}         # ( 通常の辞書を作成 )
d['ham']             # KeyError  ( 存在しないないキーを指定するとKeyErrorが発生する )

from collections import defaultdict
def value(): # ( デフォルト値を返す関数を定義 ) return 'default-value' dd = defaultdict(value, spam=100) # ( デフォルトにvalue()関数を指定 ) dd['spam'] # 100 dd['ham'] # 'default-value' ( 存在しないキーを指定するとデフォルト値が返る ) # ( defaultdictでデータのセットをグループ化する ) dataset = [('IPA', 'Punk'), ('Ale', 'YONAYONA'), ('IPA', 'Stone'), ('Ale', 'Sierra Nevada')] d = defaultdict(list) # ( 空のリストがデフォルト値となる ) for category, name in dataset: d[category].append(name) list(d.items()) # [('IPA', ['Punk', 'Stone']), ('Ale', ['YONAYONA', 'Sierra Nevada'])] ( カテゴリーごとにグループ化された )

 

・OrderedDictオブジェクト

 ・古いバージョンのPytnonでは、辞書へのデータの挿入順は維持されていなかったため、辞書で挿入順を維持するにはOrderedDictを

  使用する必要があった

 ・Python 3.7から組み込みの辞書型がデータの挿入順を維持するようになったため、 OrderedDictを利用する状況はかなり少なくなった

move_to_end(key, last=True) last引数がTrueの場合(デフォルト)は、指定したキーを末尾に移動する。Falseの場合は先頭に移動する なし
popitem(last=True) last引数がTrueの場合(デフォルト)は、末尾の要素を取り出す。Falseの場合は先頭の要素を取り出す 取り出したオブジェクト
from collections import OrderedDict

d = OrderedDict(one=1, two=2, three=3)  # ( OrderedDictを作成 )
d                                       # OrderedDict([('one', 1), ('two', 2), ('three', 3)])

d.move_to_end('two')                    # ( 指定したキーを末尾に移動 )
d                                       # OrderedDict([('one', 1), ('three', 3), ('two', 2)])

d.move_to_end('two', last=False)        # ( 先頭に移動 )
d                                       # OrderedDict([('two', 2), ('one', 1), ('three', 3)])

d.popitem()                             # ('three', 3)  ( 末尾の要素を取り出す )
d.popitem(last=False)                   # ('two', 2)    ( 先頭の要素を取り出す )

 

・namedtupleオブジェクト

 ・名前付きタプルは、タプルの各値に意味を割り当て、インデックスの代わりに属性名で値にアクセスできる

 ・namedtuple(typename, field_name)

  typename:作成するタプル型の型名を指定

  field_name:タプルの要素名を指定。スペースかカンマ区切りの文字列で指定

 ・ただし、各値に属性名を付けてアクセスする用途は、Python 3.7で追加されたdataclassを利用すると便利

from collections import namedtuple

Pet = namedtuple('Pet', 'animal, name, age')  # ( タプル名:'Pet'、要素名:'animal, name, age' )
seven = Pet('ferret', 'せぶん', 3)            # ( Pet型のインスタンスを作成 )
seven                              # Pet(animal='ferret', name='せぶん', age=3)  (「名前=値」の形式で確認できる )
seven.age                          # 3  ( 属性名で値を取得 )
seven[1]                           # 'せぶん'  ( インデックスでもアクセスできる )

michiko = Pet('cat', 'ミチコ', 1)  # ( 別のインスタンスを作成 )
a, b, c= michiko                   # ( アンパック代入も可能 )
a                                  # 'cat'

 

・enum(イーナム)モジュール

 ・enumモジュールは列挙型を定義する

 ・列挙型は、定数値に名前を定義する場合に使用する

 ・定数名は大文字で書くことが推奨される

# 定数値を定義する方法 
import enum
class Example(enum.Enum):
    名前1 = 値1
    名前2 = 値2
    名前3 = 値3

  ・「値」にenum.auto()を使うと、各定数に連番を振ることができる

import enum
class Nengo(enum.Enum):
    SHOWA = enum.auto()   # ( 1が設定される )
    HEISEI = enum.auto()  # ( 2が設定される )
    REIWA = enum.auto()   # ( 3が設定される )

 ・クラスデコレーターenum.uniqueを指定した列挙型は、複数の定数に同じ値を設定するとValueErrorが送出される

 ・定数を呼び出す

Nengo.REIWA      # ( 「.」の後ろに定数名前を書いて呼び出す )
Nengo['REIWA']   # ( 定数の名前を文字列として渡して呼び出す )
Nengo(3)         # ( 定数の値を渡して呼び出す )

 ・定数の名前と値は、name属性とvalue属性で取得できる

showa = Nengo.SHOWA
showa.name       # 'SHOWA'  ( 定数の名前 )
showa.value      # 1  ( 定数の値 )

 ・列挙型は、定数を定義順に取得するイテレーターを返す。このイテレーターは、重複する値の定数は1つだけしか取得しない

import enum
class
Spam(enum.Enum):
HAM = 1 EGG = 2 BACON = 1 # ( 重複値:出力されない。重複する値を定義する設計は極力避ける ) list(Spam) # [<Spam.HAM: 1>, <Spam.EGG: 2>]

  ・定数同士を比較

  ・同じ列挙型に定義された定数同士を==演算子で比較する場合、値が同じであればTrueと判定される

  ・異なる列挙型に定義された定数、または列挙型以外の値と比較した場合、値が同じであってもFalseと判定される

import enum
class
Spam(enum.Enum):
HAM = 1 EGG = 2 BACON = 2 isinstance(Spam.HAM, Spam) # True ( HAM、EGG、BACONはSpam型のインスタンス ) Spam.HAM == Spam.EGG # False ( 異なる値との比較 ) Spam.EGG == Spam.BACON # True ( 別の名前でも値が同じなら等しい )

  

・itertools(イテレータツール)オブジェクト

 ・イテレーターの組み合わせでいろいろな処理を実装するための各種ツールを提供

 ・通常のPythonコードでも同様の処理ができるが、itertoolsを使うと高速でメモリ効率が良く大量データを扱う場合に向いている

 ・chain()関数は、複数のイテラブルオブジェクトを連結したイテレーターを作成する

import itertools
it = itertools.chain(['A', 'B'], 'ab', range(3)) # ( リスト、文字列、rangeを連結 ) print(list(it), end=',') # ['A', 'B', 'a', 'b', 0, 1, 2],

 ・groupby()関数は、指定したイテラブルオブジェクトから値を取得し、連続する同じ値をグループにして返すイテレーターを作成する

import itertools
for value, group in itertools.groupby('aaabbcaa'): # ( 同じ文字ごとにグループ化する ) print(f'{value}: {list(group)}') # ( 各要素とイテレーターをリストに変換して確認 ) # a: ['a', 'a', 'a'] # b: ['b', 'b'] # c: ['c'] # a: ['a', 'a'] # ( 同じ'a'でも連続していないとグループ化されない )

 ・islice()関数(アイスライス)はiterable引数に大きさが不明なジェネレーターや、メモリに乗らない巨大なファイルなどを指定できる

  そのようなデータから一部を切り出したい場合は、islice()関数が便利

import itertools

li = list(range(10))
li  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
islice_object = itertools.islice(li, 5)  # ( リストの最初の5要素を返す )
islice_object                            # <itertools.islice object at 0x1089de8b0>
list(islice_object)                      # [0, 1, 2, 3, 4]  ( リストに変換して確認する )

 ・zip()関数は、指定した複数のイテラブルオブジェクトから1つずつ値を取得し、タプルの要素として返すイテレーターを作成する

  長さが異なるイテラブルオブジェクトを指定した場合は、短いほうの長さにそろえられるので注意

it1 = (1, 2)
it2 = ['abc', 'ABC', '123']
it3 = 'あいう'
for v in zip(it1, it2, it3):
   print(v)

Result

(1, 'abc', 'あ')

(2, 'ABC', 'い')

 

 ・zip()関数は短い方にあわせるが、zip_longest()関数は長い方にあわせる。足りない部分にはNoneが入るがfillvalueでデフォルト

  値を指定できる

import itertools

it1 = (1, 2)
it2 = ['abc', 'ABC', '123']
it3 = 'あいう'
for v in itertools.zip_longest(it1, it2, it3, fillvalue='-'):
    print(v)

Result

(1, 'abc', 'あ')

(2, 'ABC', 'い')

(-, '123', 'う')

 

  ・product()関数は、複数のイテラブルオブジェクトを指定し、各イテラブルオブジェクトのすべての要素の組み合わせを返す
  入れ子になったforループと同様の結果とる

import itertools

list(itertools.product('ABC', [1, 2, 3]))                 
# [('A', 1), ('A', 2), ('A', 3), ('B', 1), ('B', 2), ('B', 3)] [x[0] + x[1] for x in itertools.product('ABC', repeat=2)]
# ['AA', 'AB', 'AC', 'BA', 'BB', 'BC', 'CA', 'CB', 'CC'] ( repeat:値を組み合わせる回数 )

 

 ・permutations()関数は1つのイテラブルオブジェクトを指定し順列を返す。結果を確認すると同じ組み合わせが存在しないことがわかる

import itertools

list(itertools.permutations('ABC'))
# [('A', 'B', 'C'), ('A', 'C', 'B'), ('B', 'A', 'C'), ('B', 'C', 'A'), ('C', 'A', 'B'), ('C', 'B', 'A')]

results = itertools.permutations('ABC', 2)  # ( 長さを指定 )
[x[0] + x[1] for x in results]              # ( AA、BBといった同じ組み合わせが存在しない )
# ['AB', 'AC', 'BA', 'BC', 'CA', 'CB']

  ・combinations()関数は、指定したイテラブルオブジェクトから、指定した長さのタプルを返す

  permutations()と異なり、('A', 'B')が存在する場合、('B', 'A')は出力されない

import itertools

results = itertools.combinations('ABC', 2)
[x[0] + x[1] for x in results]
# ['AB', 'AC', 'BC']

  ・combinations_with_replacement()関数は、combinations()関数と同様の組み合わせを作成する

  同じ値の繰り返しも含むところが異なる点

import itertools

list(itertools.combinations_with_replacement('ABC', r=2))
# [('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'B'), ('B', 'C'), ('C', 'C')]

 

・copyモジュール

 ・イミュータブル(不変的な) ミュータブル(変更可能な)

 ・リストオブジェクトを別の変数に代入して、代入先の値の1つを変更すると、元のリストオブジェクトも同様に変更される

values = ['a', 'b', 'c', 'd']
v_ref = values
v_ref[1] = 'e'
v_ref           # ['a', 'e', 'c', 'd']
values          # ['a', 'e', 'c', 'd']

 ・参照元のオブジェクトを変えたくない場合はcopy()関数を使う

 ・浅いコピー(Shallow Copy)を行うcopy()関数と、深いコピー(Deep Copy)を行うdeepcopy()関数の2つがある

 ・copy()関数は1階層のみの浅いコピーに使用される。コピー先の2階層目より深い層を変更するとコピー元のオブジェクトも変更される

import copy

# 一階層 values = ['a', 'b', 'c', 'd'] val_cp = copy.copy(values) # ( copy()関数を使用してコピー ) val_cp[1] = 'e' # ( コピー先を変更 ) val_cp # ['a', 'e', 'c', 'd'] ( コピーしたオブジェクトが変更されている ) values # ['a', 'b', 'c', 'd'] ( コピー元のオブジェクトは変更されていない ) # 二階層より深い層 values = [[0, 1], [2, 3]] val_cp = copy.copy(values) val_cp.append([4, 5]) # ( コピー先を変更 ) val_cp # [[0, 1], [2, 3], [4, 5]] values # [[0, 1], [2, 3]] ( コピー元は変更されてない ) val_cp[1][0] = 8 # ( 子オブジェクト(2階層目)を変更 ) val_cp # [[0, 1], [8, 3], [4, 5]] values # [[0, 1], [8, 3]] ( コピー元も変更される )

  ・deepcopy()関数は新しいオブジェクトを作成し、そのなかに存在する子オブジェクトを再帰的にコピーする

  deepcopy()関数ではすべての階層をコピーするため、階層が深くなればなるほど時間がかかる

import copy
values = [[0, 1], [2, 3], [4, 5]] val_cp = copy.deepcopy(values) val_cp[1][0] = 8 # ( 2階層目の値を変更する ) val_cp # [[0, 1], [8, 3], [4, 5]] ( コピー先オブジェクトが変更されている ) values # [[0, 1], [2, 3], [4, 5]] ( コピー元のオブジェクトは変更されていない )

Chapter10 汎用OS・ランタイムサービス

・OSモジュール - OSの機能を利用

 ・実行中のプロセス属性の操作

  ・実行中のプロセスの属性についての機能の大半はUnix系OSの機能に依存しているため、Windowsでは利用できないものが多くある

  ・os.environに格納されているのは、最初にosモジュールがインポートされたタイミングの環境変数

  ・「最初に」というのは、通常はPython起動時にsite.pyが処理されるなかで行われる

  ・それ以降に変更された環境変数は反映されないため、os.environを直接変更する必要がある

  ・セットした環境変数は実行中のプロセスにのみ反映されているため、別のプロセスとの間で値を共有できない

環境変数 environ(エンヴァイロン)、getenv() setenv()
ユーザーID getuid()、setuid()、geteuid()、seteuid()
グループID getgid()、setgid()、getgroups()、setgroups()
プロセスID getpid()、getpgid()、 getppid()
スケジューリング優先度 getpriority()、setpriority()
import os 

os.environ['HOME']        # ( ユーザーのホームディレクトリが格納された環境変数 )
# '/home/example' 
os.environ['HAM'] = 'egg' # ( 新しい環境変数をセット )

 

 ・ファイルとディレクトリの操作

  ・osモジュールは、低レイヤーなファイル操作の機能を提供。低レイヤーとは、ハードウェアに近い部分、つまり

   OSカーネルやコンパイラ、CPUなどを開発する技術のことで、エンドユーザーが直接触れるアプリケーション層

   よりも、より基盤となる部分を指す

  ・ファイルとディレクトリの操作に関するコードを書く際は、osモジュールより使いやすいインターフェースの

   pathlibモジュールを使うのがお勧め

関数名 解説 戻り値 利用でき る環境 pathlibモジュールにある同等の関数
chdir(path) 現在の作業ディレクトリをpathに設定する None Unix、Windows  ―
chmod(path, mode, *, dir_fd=None, follow_symlinks=True) pathで指定されたファイルまたはディレクトリのモードを変更する None Unix Path.chmod ( )
chown(path, uid, gid, *, dir_fd=None,  follow_symlinks=True) path で指定されたファイルまたは ディレクトリの所有者とグループを 変更する None Unix
getcwd() 現在の作業ディレクトリを返す str Unix、Windows Path.cwd( )
listdir(path='.') pathで指定されたディレクトリ内のファイルとディレクトリを返す list Unix、Windows Path.iterdir( )
mkdir(path, mode=0o777, *, dir_fd=None) pathで指定されたディレクトリを作成する None Unix、Windows Path.mkdir( )
makedirs (name, mode=0o777. exist_ok=False) nameで指定されたディレクトリを再帰的に作成する。 末端ディレクトリだけでなく、中間ディレクトリも作成する None Unix、Windows Path.mkdir( )
remove(path, *, dir_fd=None) pathで指定されたファイルを削除する。 ディレクトリの場合はOSErrorが送出される None Unix、Windows Path.unlink( )
removedirs(name)  nameで指定されたディレクトリをパスの末端から再帰的に削除する None Unix、Windows
rename(src, dst, *, src_dir_fd=None, dst_dir_fd=None) ファイルまたはディレクトリのパスをsrcから dstに変更する None Unix、Windows Path.rename( )
renames (old, new) ファイルまたはディレクトリのパスをoldからnewに変更する。newで指定したパスにmakedirs()のように中間ディレクトリを作成し、oldで指定したバスはremovedirs()のように末端のディレクトリから再帰的に削除する None Unix、Windows
rmdir(path, *, dir_fd=None) pathで指定されたディレクトリを削除する。 ディレクトリが空でない場合はOSErrorを送出する None Unix、Windows Path.rmdir( )
symlink(src, dst, target_is_directory=False, *,  dir_fd=None) srcを指すシンボリックリンクを、dstで指定したファイル名で作成する。target_is_directoryはWindowsのみで使える引数で、Truならディレクトリとして、 False ならファイルとしてシンボリックリンクが作られる None Unix、Windows Path.symlink_to( )
import os

os.getcwd()       # '/home/example'   ( 現在の作業ディレクトリを取得 )
os.chdir('/tmp')  # ( /tmpディレクトリに移動 )
os.mkdir('test')  # ( testディレクトリを作成 )
os.listdir('.')   # ( 現在のディレクトリ内のファイルとディレクトリのリストを取得 ['test'] )
os.rmdir('test')  # ( testディレクトリを削除 )

 

・ioモジュール - ストリームを扱う

 ・ストリームとは、プログラミングでデータの入出力を行うもの(メモリ、ファイル、ネットワークなど)を抽象化した概念

 ・さまざまなI/Oのストリームオブジェクトを提供する

 ・組み込み関数open()によって生成されるファイルオブジェクトも、データ操作の対象がファイルであるストリームオブジェクト

 ・このモジュールが提供するクラスは以下のとおり

  ・文字列をファイルと同じインターフェースで扱うStringIOクラス

  ・バイト列をファイルと同じインターフェースで扱うBytesIOクラス

  ・その他、ストリームオブジェクトの抽象基底クラス群

 

 ・StringIOクラスから生成されるインスタンスは、文字列をファイルのように扱える。

  これはファイルオブジェクトとは異なり、データをメモリ上で扱う

メソッド名 解説 戻り値
read(size=-1) ストリームの現在のオフセットから指定サイズまでの文字列を返す。size が負の値またはNoneなら EOFまで読む str
write(s) ストリームに文字列を書き込む int
tell()

現在のオフセットを返す

オフセットとは、ある基準位置から相対的な位置を示す数値のこと

int
seek (offset, whence=SEEK_SET)

 オフセットを指定位置に移動する。

offset は whence で指定される位置の相対位置となる

whenceに指定可能な値は以下のとおり

・SEEK_SET:ストリームの先頭を指す。 offset には0または

 TextIOBase.tell()が返す値を指定できる

・SEEK_CUR: 現在のストリーム位置を指す。 offset には0のみ 指定できる

・SEEK_END:ストリームの末尾を指す。 offset には0のみ指定 できる

int
getvalue() ストリームが保持しているすべての内容を文字列として返す str
close() ストリームを閉じる。 閉じたあとにストリームを操作すると例外を送出する None
# StringIOクラスで文字列をファイルとして扱う
import io 

stream = io.StringIO("this is test\n")  # ( 初期値を渡すことができる )
stream.read(10)                         # 'this is te'  ( ストリームから指定サイズだけ読み出す )
stream.tell()                           # 10  ( 現在のオフセットを返す )
stream.seek(0, io.SEEK_END)             # 13  ( オフセットをストリームの末尾に変更する )
stream.write('test')                    # 4   ( ストリームに文字列を書き込む  )
print(stream.getvalue())                # ( ストリームが保持するすべての内容を返す )
# this is test
# test
stream.close()                          # ( ストリームを閉じる 
stream.write('test')                    # ValueError  ( 閉じたあとに書き込もうとすると例外を送出する )

with io.StringIO() as stream:           # ( withブロックを使うことで暗黙的にclose()を呼ぶこともできる )
    stream.write('test')

the_zen_of_python = """The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
""" 
stream = io.StringIO(the_zen_of_python)
for line in stream:                     # ( for文で1行ずつ読み込むこともできる )
    print(line, end='')
# The Zen of Python, by Tim Peters
# Beautiful is better than ugly
# Explicit is better than implicit.
# Simple is better than complex.\n'
# Complex is better than complicated.

 

 ・BytesIOクラスから生成されるインスタンスは、bytesオブジェクトをファイルのように扱える。StringIOクラスと同じく、

  データをメモリ上で扱う

メソッド名 解説 戻り値
read(size=-1) ストリームの現在のオフセットから指定サイズまでのバイト列を返す。size が負の値またはNoneなら EOFまで読む str
write(s) ストリームにバイト列を書き込む int
tell()  StringlOクラスのtell() メソッドと同じ int
seek (offset, whence=SEEK_SET)  StringIOクラスのseek() メソッドと同じ int
getbuffer()

バッファーの内容を返す。この値は読み込みおよび書き込みが可能なビュー

値を更新すると、 バッファーの内容も同様に更新される

memoryview
getvalue() バッファーの内容を返す。 この値は更新ができない bytes
close() StringlOクラスのclose() メソッドと同じ None
# BytesIOクラスの基本的な使い方
import io

stream = io.BytesIO(b'abcdefg')         # ( 初期値を渡すことができる )
stream.read(5)                          # b'abcde'  ( ストリームから指定サイズだけ読み出す )
stream.tell()                           # 5  ( 現在のオフセットを返す )
stream.seek(0, io.SEEK_END)             # 7  ( オフセットをストリームの末尾に変更する )
stream.write(b'test')                   # 4  ( ストリームに文字列を書き込む )
print(stream.getvalue())                # b'abcdefgtest'  ( ストリームが保持するすべての内容を返す )
stream.close()                          # ( ストリームを閉じる )
stream.write(b'test')                   # ValueError  ( 閉じたあとに書き込もうとすると例外を送出する )

with io.BytesIO() as stream:            # ( withブロックを使うことで暗黙的にclose()を呼ぶこともできる )
    stream.write(b'test')

stream = io.BytesIO(b'abcdefg')
view = stream.getbuffer()               # ( 読み込みおよび書き込みが可能なビューを返す )
view[2:4] = b'56' 
print(stream.getvalue())                # b'ab56efg'  ( ビューの更新結果が反映される )

 

・sysモジュール - インタープリターに関わる情報を取得、操作する

 ・sys.argv(アーグ・ブイ)は、Pythonスクリプト実行時に渡された引数が格納されたリスト。sys.argv[0]は実行されたファイル名

  ・複雑なコマンドライン引数を処理する場合はargparse(アーグ・パーズ)モジュールを使うと少ないコードで柔軟な引数の処理を実装できる

 

 ・sys.pathは、インポート対象のモジュールやパッケージを探索する先となるファイルパスを格納したリスト

  ・sys.pathにファイルパスを追加することで、そこに置かれたPythonパッケージやモジュールをimport文でインポートできる

  ・sys.pathは以下の要素で初期化される

   ・実行されたPythonスクリプトのあるパス

   ・環境変数PYTHONPATHに設定されたパス

   ・Pythonのインストール先

# 以下のように、Pythonスクリプトが置かれたディレクトリを環境変数PYTHONPATHに指定して対話モードを起動
$ ls /home/my/scripts
myscript.py

$ PYTHONPATH=/home/my/scripts python  # 設定値中のpythonは、シェルが実行する Pythonインタプリタ(実行プログラム)のこと

# PYTHONPATHが指定された状態のsys.pathの値を確認する 
import pprint, sys

pprint.pprint(sys.path) 
# ['',                   ( 対話モードとして起動された、空文字列がリスト先頭に設定された )
# '/home/my/scripts',    ( 環境変数で設定したパス )
# '/usr/lib/python3.9',  ( 以降はPythonのインストール先から設定されるため環境によって異なる )
# '/usr/lib/python3.9/plat-x86_64-linux-gnu', 
# '/usr/lib/python3.9/lib-dynload', 
# '/usr/local/lib/python3.9/dist-packages', 
# '/usr/lib/python3/dist-packages'] 

import myscript          # PYTHONPATHで設定したディレクトリ内のモジュールをインポートできる

 

 ・sys.exit()関数は、呼び出した時点でPythonスクリプトの実行を終了する

  ・引数argには終了ステータスを指定できる。数値以外のオブジェクトを渡した場合は、渡されたオブジェクトを文字列として

   sys.stderrに出力し、呼び出し元に終了コード1を返して終了する。また、引数を省略した場合は終了コード0として終了する

   一般に、終了コード0は正常終了、それ以外は異常終了を表す

$ vim exit.py
import sys 
sys.exit('プログラムを終了します')

$ python exit.py
# プログラムを終了します

$ echo $?  # ( 直前に実行されたコマンドの終了コードを出力する )
# 1

 

 ・sys.stdin()関数、sys.stdout()関数、sys.stderr()関数はインタープリターが使用するコンソールの入出力用のオブジェクト

  ・sys.stdinは、標準入力オブジェクト(読み込み専用)

  ・sys.stdoutは、標準出力オブジェクト(書き込み専用)

  ・sys.stderrは、標準エラーオブジェクト(書き込み専用)

  ・sys.stdin.read()はinput()関数で置き換えることができる。sys.stdout.write()はprint()関数で置き換えることができる

sys.stdout.write('standard output message\n')
# standard output message     ( 標準出力された文字列 )
# 24                          ( write()メソッドの戻り値 )

sys.stderr.write('standard error message\n') 
# standard error message      ( 標準エラー出力された文字列 )
# 23                          ( write()メソッドの戻り値 )

sys.stdin.read() 
standard input message        # 端末に任意の文字列を入力して改行
# 'standard output message\n' ( 終わらせるには、通常、Ctrl+D(Linux/MacOS)またはCtrl+Z(Windows)を入力する )

 

 ・sys.breakpointhook()関数は、組み込み関数のbreakpoint()でデバッグを開始した際に呼ばれるフック関数

  ・breakpoint()関数はデフォルトではpdbデバッガーが呼ばれるが、sys.breakpointhook()に関数を渡すことで挙動を

   変えることができる

  ・また、breakpoint()関数で呼びたい関数の名前を環境変数PYTHONBREAKPOINTに渡しても同じことができる

# sys.breakpointhookの内容をprint_hello()関数にしたことで、pdb以外の処理が実行される
import sys

def print_hello():
    print('Hello!')

sys.breakpointhook = print_hello

if __name__ == '__main__':
    print('start')
    breakpoint()  # ここでprint_hello()が呼ばれる
    print('end')

 

 ・sys.version_infoはPythonのバージョン番号を調べることができる

  ・バージョン番号は5つのタプル(major、minor、micro、releaselevel、serial)で構成されている。releaselevel以外はすべて整数

import sys
sys.version_info
sys.version_info(major=3, minor=9, micro=7, releaselevel='final', serial=0)

 

・argparseモジュール - コマンドラインオプション、引数を扱う

 ・--stringや--numのような長いオプションと同じ名前の変数に値が格納されるため、args.stringやargs.numとして値にアクセスできる

# *** パーサーの作成とオプションの定義 ***
# 以下は、引数の1つに文字列、もう1つの引数に整数を受け取り、指定された数だけ繰り返し文字列を表示するだけのスクリプト
import argparse parser = argparse.ArgumentParser(description='Example command') # ( パーサーのインスタンスを作成 ) # -sオプション:文字列を受け取る、-nオプション:数値を受け取る parser.add_argument('-s', '--string', type=str, help='string to display', required=True) # ( required:必須) parser.add_argument('-n', '--num', type=int, help='number of times repeatedly display the string', default=2) args = parser.parse_args() # ( 引数をパースし、得られた値を変数に格納する ) print(args.string * args.num) # ( パースによって得られた値を扱う )

  ・パーサー全体の挙動はArgumentParser(アーギュメント・パーサー)の初期化引数により指定

引数名 解説 デフォルト値
prog プログラム名を指定する sys.args[0]
usage プログラムの利用方法を文字列で指定する パーサーに渡された引数から生成される
description 引数のヘルプの前に表示される文字列を指定する None
epilog 引数のヘルプのあとに表示される文字列を指定する None
parents ArgumentParser オブジェクトのリストを指定する。このリストに含まれるオブジェクトの引数が追加される []
formatter_class ヘルプとして表示されるフォーマットをカスタマイズするためのクラスを指定する argparse.HelpFormatter
prefix_chars 引数の先頭の文字を指定する。 通常は -o だが、 たとえば + を指定すると +o のような引数になる '-'
fromfile_prefix_chars 引数をファイルに記述して読む込む際にファイル名の前に付ける文字を指定する。 たとえば @ を指定すると@file.txtのようにファイルを指定できる None
argument_default パーサー全体に適用される引数のデフォルト値を指定する None
conflict_handler 1回のコマンド呼び出しで、あるオプションが複数指定された場合の挙動を指定する。 デフォルトではエラーになる  'error'
add_help -hオプションをパーサーに追加するかどうかを指定する True
allow_abbrev 長い名前のオプションを先頭の1文字に短縮できるようにする hoge
exit_on_error エラー発生時の挙動を変更する。True の場合はエラーメッセージを表示させて終了する。 False の場合は argparse.ArgumentError 例外を送出する hoge

 

 ・前述「パーサーの作成とオプションの定義」をrepeat.pyとして保存した実行例

# 引数なしで実行。実行エラーとなる
$ python repeat.py
usage: repeat.py [-h] -s STRING [-n NUM]
repeat.py: error: the following arguments are required: -s/--string

# -hを指定した場合。ヘルプが表示される
$ python repeat.py -h
usage: repeat.py [-h] -s STRING [-n NUM]

Example command

options:
  -h, --help            show this help message and exit
  -s STRING, --string STRING
                        string to display
  -n NUM, --num NUM     number of times repeatedly display the string

# 引数した場合。正常に処理される
$  python repeat.py -s hoge -n 3
hogehogehoge 

 

 ・add_argument()メソッドに指定できる代表的な引数

引数名 解説 デフォルト値
nameまたはflags オプションの名前、 またはオプション文字列のリストを指定する なし
action 引数に値が渡された際のアクションを指定する 'store'
default 値が渡されなかった場合のデフォルト値を指定する None
type 渡された値を指定した型に変換する 'str'
choices 引数として許される値を格納したコンテナー型 (list dict など) の値を指定する None
required 引数が必須かどうかを指定する False
help 引数を解説する文字列を指定する None

 

 ・読み取る対象のファイルパスをオプションで指定

# argparse.FileTypeの使用例
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--input', type=argparse.FileType('r'), required=True)

args = parser.parse_args()
print(args.input.read())


# 上記のコードをread_file.pyというファイル名で保存
$ python read_file.py --input ./spam.txt  # ( 存在しないファイル名を指定 )
usage: read_file.py [-h] --input INPUT
read_file.py: error: argument --input: can\'t open './spam.txt': [Errno 2] No such file or directory: './spam.txt'

 

Chapter14 インターネット上のデータを扱う

・urllib.parse - URLをパースする

 ・urlparse()を使うことで、URLを表す文字列をアドレススキーム、ネットワークロケーション、パスなどの構成要素に分解できる

from urllib import parse

result = parse.urlparse('https://www.example.com/test/;parameter?q=example#hoge')
result             # ( パースの結果を返す )
# ParseResult(scheme='https', netloc='www.example.com', path='/test/', params='parameter', query='q=example', fragment='hoge') 
result.geturl()    # ( パース結果からURLを取得する )
# 'https://www.example.com/test/;parameter?q=example#hoge
result.scheme      # ( タプルの要素に名前でアクセスする )
# 'https' 
result[0]          # ( タプルの要素にインデックスでアクセスする )
# 'https' 
result.hostname    # ( タプルの要素以外にもいくつかの属性を持つ )
# 'www.example.com'

   ・ParseResultはタプルのサブクラス。タプルと同様にアンパックしたり、スライスを使って要素にアクセスしたりできる

属性 インデックス URLの対応箇所 URLに該当箇所が存在しない場合の値
scheme 0 URLスキーム (http https など) scheme schemeパラメーター
netloc 1 ネットワーク上の位置 username:password@netloc:port 空文字
path 2 パスの階層 /path 空文字
params 3 URL引数 (「;」以降の文字列) ; params 空文字
query 4 クエリ文字列(?hoge=hoge&fuga=fuga) ?query 空文字
fragment 5 フラグメント識別子 (「#」以降 の文字列) #fragment 空文字
username ユーザー名 username None
password パスワード password None
hostname ホスト名 netloc None
port ポート番号 port (実際は数値) None

 

 ・parse_qs()は、URLの末尾に付けられた「?」マーク以降をクエリ文字列としてパースし、Pythonの辞書に変換する

  parse_qsl()では、各ペアを1つのタプルのリストとして受け取ることができる

result = parse.urlparse('https://www.google.co.jp/search?q=python&oq=python&sourceid=chrome&ie=UTF-8')

result.query # 'q=python&oq=python&sourceid=chrome&ie=UTF-8
parse.parse_qs(result.query) # ( パース結果を辞書として受け取りたい場合 ) # {'q': ['python'], 'oq': ['python'], 'sourceid': ['chrome'], 'ie': ['UTF-8']} parse.parse_qs('key=1&key=2') # ( 1つのキーに対して値が複数ある場合の例 ) {'key': ['1', '2']}
parse.parse_qsl(result.query) # ( パース結果をタプルのリストとして受け取りたい場合 ) # [('q', 'python'), ('oq', 'python'), ('sourceid', 'chrome'), ('ie', 'UTF-8')] parse.parse_qsl('key=1&key=2') # ( 値が複数ある場合、parse_qsとは異なり2つのタプルとなる ) # [('key', '1'), ('key', '2')]

 ・urlencode()は、Pythonのタプルや辞書からapplication/x-www-form-urlencodedに従ってエンコードされたクエリ文字列を作成する

  結果はASCIIテキスト文字列に変換され、&文字で区切られたキーと値のセットを返す

  ・引数queryには、辞書などのマッピング型オブジェクトか2要素のタプルのリストを渡すことができます。

parse.urlencode({'key1': 1, 'key2': 2, 'key3': 'ぱいそん'})
# 'key1=1&key2=2&key3=%E3%81%B1%E3%81%84%E3%81%9D%E3%82%93'

parse.urlencode([('key1', 1), ('key2', 2), ('key3', 'ぱいそん')])
# 'key1=1&key2=2&key3=%E3%81%B1%E3%81%84%E3%81%9D%E3%82%93'

 ・quote()関数は、文字列をURLとして使用できるようにパーセントエンコードした結果を作成する

  URLに含まれる特殊文字や日本語などの2バイト文字を変換する場合に利用される

  ・quote_plus()もパーセントエンコードした結果を返すのは同じだが、以下の点が違う

   ・スペース:quote()は「%20」に変換するが、quote_plus()は「+」に変換する

   ・safe引数のデフォルト値:quote()は「/」が設定されておりエンコードされないが、quote_plus()は空文字のためエンコードされる

  ・quote()やquote_plus()でエンコードされない文字列:「_.-~」

url = 'https://ja.wikipedia.org/wiki/パイソン'

parse.quote(url)
#'https%3A//ja.wikipedia.org/wiki/%E3%83%91%E3%82%A4%E3%82%BD%E3%83%B3'

parse.quote_plus(url) 
# 'https%3A%2F%2Fja.wikipedia.org%2Fwiki%2F%E3%83%91%E3%82%A4%E3%82%BD%E3%83%B3'

  ・urljoin()関数は、ベースとなるURL文字列に文字列を結合して、別のURL文字列を返。あるURLに対してファイル名だけ変更したい、

  またはパスだけ変更したURLを作成したい場合に利用する

from urllib import parse 

# URLとパスを結合
parse.urljoin('https://ja.wikipedia.org', '/wiki/Python')
# 'https://ja.wikipedia.org/wiki/Python' 

# パスに相対パスを指定した場合
parse.urljoin('https://ja.wikipedia.org/wiki/Python', '#ライブラリ')
# 'https://ja.wikipedia.org/wiki/Python#ライブラリ'

parse.urljoin('https://ja.wikipedia.org/test/path/', '../../wiki/Python')
# 'https://ja.wikipedia.org/wiki/Python' 

# base、urlともにURLを指定した場合はurlが返される 
parse.urljoin('https://www.python.org/', 'https://www.example.com')
# 'https://www.example.com'

 

・urllib.request - URLを開く

 ・urlopen()はurllib.requestモジュールでURLを開くための代表的なインターフェース

 


第12章 Python仮想環境とサードパーティパッケージの利用

・仮想環境

 ・複数のPythonの実行環境を目的に応じて使い分けられる

 ・使用するPythonのバージョンは仮想環境ごとに指定できる

 ・使用する外部パッケージの種類とバージョンも選択可能

 ・1つの仮想環境でパッケージのバージョンを変更しても、別の仮想環境のバージョンは変更されない

 ・仮想環境を作成するディレクトリは、コマンドで指定する。このディレクトリの中には、Pythonのインタープリタ本体やパッケージ、

  仮想環境を有効化するスクリプトなどが含まれる

  ・仮想環境に使うバージョンのPythonは、あらかじめインストールしておく必要がある

 

・仮想環境の導入方法

 ・仮想環境の作成には、venv(ブイエンブ)モジュールを使う

 ・仮想環境用のディレクトリの作成 python3 -m venv ディレクトリ名 windowsではpython3の代わりのpythonを使う

 ・UnixやmacOSにおいて、複数のバージョンのPythonがインストール済の場合にバージョンを指定できる python3.10 -m venv ディレクトリ名

 ・仮想環境に切り替える方法

  ・UnixやmacOSの場合 source ディレクトリ名/bin/activate 

  ・Windowsの場合 ディレクトリ名/Scripts/activate.bat

 

・外部パッケージのインストール

 ・外部パッケージはpip(ピップ)モジュールを使ってインストールする

 ・外部パッケージのインストール python -m pip install パッケージ名 あるいは pip install パッケージ名

 ・特定のバージョンのインストール(インストール済みでも変更可能) pip install パッケージ名==バージョン

  ・==3.1 3.1および3.1.*

  ・~=3.1 3.1以上かつ3.*

  ・>=3.1 3.1以上

 ・インストール済みのパッケージをアップグレード pip install -U パッケージ名 あるいは pip install --upgrade パッケージ名

 ・インストール済みのパッケージをアンインストール pip uninstall パッケージ名

 ・インストール、アンインストールは複数パッケージの同時指定可能 例 pip install パッケージ1 パッケージ2 パッケージ3

 ・インストール済みのパッケージを一覧出力 pip list

 ・インストール済みのパッケージをrequirements形式で一覧出力 pip freeze

Chapter1 Pythonの環境

・pip

 ・pipがインストールされていない環境での導入方法  python -m ensurepip

 ・Debian、Ubuntuでのpipの導入方法  sudo apt install -y python3-pip

 

・PyPI(パイピーアイ)

 ・PyPIとはPython用のソフトウェア・リポジトリのこと

 ・pip install パッケージ名に対してPyPIに公開されていれば、そのパッケージがインストールされる

  インストール時に依存パッケージも同時にインストールされる

$ pip install sampleproject
Collecting sampleproject
  Using cached sampleproject-2.0.0-py3-none-any.whl (4.2 kB)
Collecting peppercorn  # ( 依存パッケージ )
  Using cached peppercorn-0.6-py3-none-any.whl (4.8 kB)
Installing collected packages: peppercorn, sampleproject
Successfully installed peppercorn-0.6 sampleproject-2.0.0 

 ・ある範囲のバージョンのなかで最新のものをインストールしたい場合は、>、<、=を使ってバージョンの範囲を指定する

  この場合はダブルクオートでパッケージ名とバージョンを囲む必要がある

  pip install "sampleproject>=1.2.0,<2.0.0" 1.2.0以上2.0.0未満のなかで最新のバージョンをインストール

 ・バージョン指定と組み合わせることでダウングレードも可能(--upgrade付でも問題なし)

# 最新バージョンにアップグレード
$ pip install --upgrade sampleproject Requirement already satisfied: sampleproject in ./.venv/lib/python3.9/site-packages (1.3.1) Collecting sampleproject #(省略) Successfully installed sampleproject-2.0.0 $ pip install --upgrade sampleproject==1.2.0 # ( バージョン1.2.0にダウングレード ) Collecting sampleproject==1.2.0 Successfully installed sampleproject-1.2.0

 ・インストール済みの最新バージョンではないパッケージ一覧 pip list -o または pip list --outdated

 ・個別パッケージの詳細情報の確認(依存関係にある他パッケージも出力される) pip show パッケージ名

 ・依存関係にあるパッケージも含めて完全アンインストールする場会は個別にpip uninstallする必要がある

 ・requirements.txtを参照してパッケージと指定したバージョンを一括でインストールする pip install -r requirements.txt

 ・複数のアプリケーションを開発していて、そのすべてのアプリケーションで特定パッケージのバージョンを統一したい

  pip install -r requirements.txt -c constraints.txt

  ・constraints.txtは、統一したいパッケージのみをバージョンを付けて記載し、全てのアプリケーションの直下に記載する
   requirements.txtにそのパッケージがないと何もしない

  ・requirements.txt は、各アプリケーション毎に記載するが、統一したいパッケージにはバージョンを記載しない

   ・constraints.txtはrequirements.txtとセットで使うことが前提で、単体では使えない

 ・複数バージョンのPythonをインストールした環境でバージョンを指定してインストールする

  pip3.9 install パッケージ名 または python3.9 -m pip install パッケージ名

 

・仮想環境

 ・venvの仮想環境はDockerやVirtualBoxなどの仮想環境とは異なる

 ・仮想環境を作成する際、通常は右記のコマンドを使う python -m venv ディレクトリ名

  この時、python -m venv --upgrade-deps ディレクトリ名 とすると最初からpipコマンドは最新版でインストールされる

 ・仮想環境を有効化するとシェルプロンプトに仮想環境のディレクトリ名が表示される 例 (ディレクトリ名)

 ・仮想環境を有効化した後にpipを最新版にアップグレードする pip install --upgrade pip

 ・仮想環境の利用が終わったら無効化する deactivate

 ・不要になった仮想環境を削除 rm -rf ディレクトリー名

 ・パッケージのアンインストールを行っても依存関係にあるパッケージはアンインストールされないので

  一旦削除して仮想環境を作り直した方が手間が少ない。同じバージョンで再構築したい場合は予めrequirements.txtを作成しておく


以降は基礎にないカテゴリ

Chapter3 Python言語使用

・with文

 ・with文は、try-finallyの利用パターンをカプセル化して再利用するために追加された機能

 ・with文を使うと、同じことをtry-finallyブロックを使って書くより簡潔に書ける

# with文を使用しない例 
f = None
try:
    f = open('python.txt')
    print(f.read())
finally:
    if f:
        f.close()

# 上記の処理は下記と同じです。 

with open('python.txt') as f:
    print(f.read())

 ・コンテキストマネージャー

  ・with文に渡すオブジェクトをコンテキストマネージャー(context manager)と呼ぶ

  ・コンテキストマネージャーとは、__enter__()、__exit__()の特殊メソッドを実装したクラスのインスタンス

  ・open関数の例ではファイルオブジェクトがコンテキストマネージャーオブジェクト

  ・__enter__()が実行され、次にwithブロック内、最後に__exit__()が実行される

  ・withブロック内での例外発生時は__exit__()の引数で例外情報が受け取れる

class MyOpenContextManager:
    def __init__(self, file_name):
        self.file_name = file_name
    
    # with文が実行されると、withブロックが開始される前に__enter__()メソッドの処理が実行
    def __enter__(self):
        print('__enter__ : ファイルをopenします')
        self.file_obj = open(self.file_name, 'r')
        return self.file_obj  # ( __enter__で返したオブジェクトはasキーワードで参照できる )
        
    # withブロックの終了したあとに__exit__()メソッドの処理が実行される
    def __exit__(self, type, value, traceback):
        print('__exit__ : ファイルをcloseします')
        self.file_obj.close()

with MyOpenContextManager('python.txt') as f:
    print(f.read())

Result

__enter__ : ファイルをopenします

Python!

__exit__ : ファイルをcloseします  (「Python!」はpython.txtの中身)

 

 ・@contextlib.contextmanager

  ・@contextlib.contextmanagerデコレーターを使用してジェネレーター関数を記述するとコンテキストマネージャーを定義できる

   それにより、__enter__()と__exit__()メソッドを別々に定義したクラスを書く必要がない

   ・デコレーターとは、既存関数に別の処理を追加する仕組み

   ・ジェネレーター関数とは、リターン時の状態を保持し、再呼び出し時は保持された状態から処理されるも

  ・さきほどのMyOpenContextManagerクラスと同等のコンテキストマネージャーを実装したもの

   ・yield文より前に書かれたコードがwithブロックの開始前に実行される

   ・yield文よりあとに書かれたコードがwithブロックの最後に実行される

   ・asキーワードに値を渡したい場合は、yield文に値を渡す

   ・withブロック内で発生した例外はyield文を実行している箇所で再送出されるため、後処理を適切に行うようにするには

    try-finallyを使用する

import contextlib
import traceback
@contextlib.contextmanager
def my_open_context_manager(file_name):
    file_obj = open(file_name, 'r')
    try:
        print('__enter__ : ファイルをopenします')
        yield file_obj
    except Exception as e:
        print(f'__exit__:{type(e)}')
        print(f'__exit__:{e}')
        print(f'__exit__:{list(traceback.TracebackException.from_exception(e).format())}')
        raise
    finally:
        file_obj.close()
        print('__exit__ : ファイルをcloseします')

with my_open_context_manager('python.txt') as f:
    print(f.read())

 ・よくある使い方

  ・try-finallyの再利用

  ・ファイルのopen/close

  ・組み込み関数の書き換え

  ・ある処理の実行時間を計測したいというケースで、コンテキストマネージャーを使用した例

from time import time, sleep
import contextlib

@contextlib.contextmanager
def timed(func_name):
    start = time()
    try:
        yield
    finally:
        end = time()
        print(f'{func_name}:(total: {end - start})')

with timed('sleep processing'):
    sleep(3)

 

・ジェネレーター

 ・通常の関数とおおよそ同じだが、return文の代わりにyield(ヤイルド)文を使用する

 ・関数内でyield文が使用されるとpythonはこの関数をジェネレーターと判断する

 ・yieldからはジェネレーターオブジェクト(イテラブル)が返される

 ・yield文は実行された時点の値を返し、その位置で一時停止の状態になり次の呼び出しを待つ

 ・ジェネレーターはデータ量が大量になってもメモリリースを消費することなく処理を行うことができる

 ・ジェネレータで使用できる関数の1つのnext関数は、イテレーターから次の値を取り出す組み込み関数で、

  ジェネレーターオブジェクトの__next__()メソッドを呼び出している

 ・無限の数列を扱うことができるのもジェネレーターの特徴

li = []
def multiplier():
    num = 1
    while True:  # ( 無限 )
        yield num
        num *= 2

gen = multiplier()
for _ in range(3):
    li.append(next(gen))

print(li)    # [1, 2, 4]

 ・大きいファイルの処理にジェネレーターは効率的

  ・ファイル読み込みのループ処理中に対象のデータを1つずつ取り出しながら処理を行うことができるため1行分のメモリ程度ですむ

  ・対象データを処理するコードはジェネレーターとは別に記述できるため、コードが読みやすくなる

# ファイルからキーワードを含む行を抜き出すのにジェネレーターを使用
def text_retrieve(text):
    with open('sample.txt', 'r') as f:
        for row in f:
            if text in row:
                yield row       # ( 引数で指定されたキーワードを含む場合に値を返す )

def do_something_func(txt):
    print(txt)

for txt in text_retrieve('A'):  # ( 'A'というキーワードが含まれる行の取得 )
    do_something_func(txt)      # ( 対象の行に対して別の処理が行われたあとにファイル読み込みループが再開される )

 

・デコレーター

 ・関数やメソッド、クラスをデコレート(装飾)する機能。中身を変えずに共通のロジックを適用できる

 ・適用したい対象の上に「@デコレーター名」と1行追加する

 ・デコレーターはシンタックスシュガーのため以下のデコレーターの構文と代入文は等価。シンタックスシュガーとは、

  複雑でわかりにくい書き方をよりシンプルでわかりやすい別の記法で書くこと

# デコレーターの構文。func関数にmy_decoratorデコレーターを適用
@my_decorator  # ( デコレートー名 )
def func():    # ( デコレート対象の関数 )
    pass

# 代入文 
def func():
    pass
func = my_decorator(func)

 

 ・デコレーターの利点は、デコレート対象の関数には何も変更を加えていなくても、デコレーターを1行追加するだけで

  デコレート対象の関数の前後で処理を追加して実行できる

 ・以下は、デコレート対象の関数(my_func関数)にretryデコレーターを適用して実行する例。retryデコレーターを適用することで、

  5以外の数字が生成され例外が発生しても、再度my_func()関数が実行され、例外が発生しなくなるまで関数の実行がリトライされる

  ちなみに@retry(stop_max_attempt_number=2)のように、引数で最大リトライ回数が指定できる

$ pip install retrying

import random
from retrying import retry

@retry  # このデコレーターを1行追加するだけでmy_func関数内で例外が発生した際に再度関数の実行を行ってくれる
def my_func():
    if random.randint(0, 10) == 5:
        print('5です')
    else:
        print('raise ValueError')
        raise ValueError("5ではありません")

Result

raise ValueError

raise ValueError

5です

 

 ・クラスデコレーター

  ・クラスや、クラスメソッドにもデコレーターを適用できる

  ・使い方は関数デコレーターと同様にクラスやメソッド定義の前に「@デコレーター名」で1行追加するだけ

 

 ・複数デコレーター

  ・1つの関数やメソッド、クラスに複数のデコレーターを適用できる。1行ごとに1つのデコレーターを指定する

  ・デコレーターは内側から外側に向かって順に適用される

# func()関数にmy_decorator2が適用されたものがmy_decorator1に渡される
@my_decorator1
@my_decorator2
def func():
   pass

 

  ・関数デコレーターを自作

func = my_decorator(func)  # ( 代入文 )

   デコレーターもただの関数。my_decorato関数(デコレーター)はfunc関数を引数にとり、返された結果をfuncに代入する

   ことでfuncを置き換えている。 言葉で説明すると難しく感じるが、Pythonの関数の仕様を理解するとそれほど難しくはない

   まずは、順を追ってPythonの関数について確認

# 関数内に関数を定義する
def func_greeting(name):       # ( 関数内にprint_greeting()という1つの関数を定義 )
    def print_greeting():
        print(f'{name} さん')  # ( nameという外側の関数に定義されている仮引数を、内側の関数内で利用できる )
    return print_greeting      # ( 関数をreturn )

func = func_greeting('john')   # ( デコレーター関数が呼ばれ、ラッパー関数が戻される ※まだラッパー処理はされない )
func()                         # ( ()を付けることでラッパー関数を実行できる。funcの中身はprint_greeting関数 )

 

# 関数を別の関数への引数として与える
def after_greeting(func, name):
    func(name)
    print('今日はいいお天気ですね')

def greeting(name):
    print(f'{name} さん')

after_greeting(greeting, 'john')  # ( greeting()という関数を別の関数の引数として渡している )

   上記をふまえ、以下にシンプルなデコレーターを代入文で作成

   以下はデコレーターの実装まとめ

   1) デコレーター関数を定義する

   2) デコレーター関数はデコレート対象の関数を引数として受け取るようにする

   3) デコレーター関数のなかにデコレート対象の関数の代わりに呼び出されるラッパー関数を定義

   4) ラッパー関数のなかでデコレーター関数の引数で受け取った関数を呼び出す

   5) 関数呼び出しの前後に追加、変更の処理を加える

   6) デコレーター関数の戻り値としてラッパー関数を返す

   7) wrap_functionは呼び出し可能オブジェクトなので、()を使用してコールできる。このオブジェクトを呼び出すと、

    my_decorator()内のwrap_function()が呼び出されて処理が実行される

# デコレーター対象の関数を呼び出したあとログ出力するデコレーター関数を代入文で作成したもの
def my_decorator(func):              # 1), 2)
    def wrap_function():             # 3)
        func()                       # 4)
        print(f'{func.__name__}')    # 5)
    return wrap_function             # 6)

# デコレーター対象の関数
def greeting():
    print('こんにちは')

greeting = my_decorator(greeting)
greeting()                           # 7)

 

  ・上記を「@デコレーター名」構文を使用して置き換える

@my_decorator
def greeting():
    print('こんにちは')

≫ 出題範囲外

タイトル 問題数

問題

割合

備考
1 Pythonの環境 1 2.50%  
2 コーディング規約 2 5.00%  
3 Pythonの言語仕様 7 17.50%  
4 Pythonのクラス 3 7.50%  
5 タイプヒント 2 5.00% 5.2 mypy は除く
6 テキストの処理 4 10.00%  
7 数値の処理 0 0.00% 出題なし
8 日付と時刻の処理 2 5.00% 8.4 dateutilは除く
9 データ型とアルゴリズム 5 12.50%

9.3 bisectは除く

9.5 pprint は除く

10 汎用OS・ランタイムサービス 2 5.00%  
11 ファイルとディレクトリへのアクセス 2 5.00%  
12 データ圧縮とアーカイブと永続化 0 0.00% 出題なし
13 特定のデータフォーマットを扱う 2 5.00%

13.3 configparser は除く

13.4 PyYAML は除く

13.5 openpyxl は除く

13.6 Pillow は除く

14 インターネット上のデータを扱う 2 5.00%

14.3 Requests は除く

14.5 emai は除く

15 HTML/XMLを扱う 0 0.00% 出題なし
16 テスト 3 7.50%

16.4 pytest は除く

16.5 pydoc は除く

17 デバッグ 2 5.00% 17.3 traceback は除く
18 暗号関連 1 2.50% 18.3 cryptography は除く
19 並行処理、並列処理 0 0.00% 出題なし

Chapter3 Python言語使用

・hoge