Python 試験


≫ Python 3 エンジニア認定基礎試験



第1章 Pythonの特徴

・コンパイルが不要

 

・インタープリター

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

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

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

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

 

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

 

・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がプログラム言語として推奨しているスタイルガイドは通称「PEP 8」と呼ばれる

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

 

・文字列の記述

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

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

 

・コメントの記述

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

 

・入力履歴ファイル

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

 ・ファイル名「.python_history」

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

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


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

・算術演算子の順序

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

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

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

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

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

 

・文字列リテラルの連結

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

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

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文字列(フォーマット済み文字列)

 ・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メソッド

 ・"文字列{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

第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

第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

 

 ・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


第5章 関数

・関数の定義

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

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

 

・関数の呼び出し

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

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

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

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

def greeting(a):
    return (a)

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

Result

Hello

 

・関数の変数

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

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

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

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

x = 100  # グローバル変数

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

do_global()
print(x)

Result

200

 

・関数の引数

  ・キーワード引数

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

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

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

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

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

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

 

 ・引数のデフォルト値

  ・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

 

》補足

・ドキュメンテーション文字列(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


第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)                                  # in演算子 True

 

 ・ディクショナリ

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

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

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

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

 ・要素の削除 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 別サブモジュール

  ・同じ階層から別サブモジュールの名前をインポート  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 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のオブジェクトや文字列に変換すること


第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     :ディクショナリに存在しないキーを参照しようとしたとき


第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は不要

 

・オブジェクトの判定

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

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

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

print(isinstance(duck, Duck))

Result

True


第11章 標準ライブラリ

・OSモジュール

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

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

 

・globモジュール

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

 

・sysモジュール

 ・sys.argv でコマンドライン情報を取得。 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個以上の任意形式の引数の指定

 ・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未満のランダムな値(少数)を返す

 

・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回繰り返し

 

 ・フラグ設定

  ・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


第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 パッケージ名=バージョン

 ・インストール済みのパッケージをアンインストール pip uninstall パッケージ名

 ・インストール、アンインストールは複数パッケージの同時指定可能 例 pip install パッケージ1 パッケージ2 パッケージ3

 ・インストール済みのパッケージ一覧 pip list