2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[資格] python3エンジニア認定基礎試験を受けるため基礎からPythonを勉強してみた(勉強編)

Last updated at Posted at 2020-01-19

ここでやったこと

Pythonチュートリアル 第3版」を中心に、WebのPython チュートリアルも見て実際に実行してみた。
このメモを取りながらのためかなり時間はかかった。
実行環境は主にCentOS7にてコマンド。
最後にJupyerNotebookでもやってみたが、こちらのほうが個人的にはやりやすかった。

1章 食欲をそそってみようか   (出題数1問,2.50%)

Pythonはインタープリタ言語

2章 Pythonインタープリタの使い方   (出題数1問,2.50%)

2.1. インタプリタの起動

(シェルで)python3.5 インタープリタの起動 ※3.5箇所は環境により異なる
>>> quit() インタープリタの終了

python -c コマンド [引数] ...
※Pythonの文はシェルにとって特殊なキャラクタを含むことが多いため、通常はコマンド部分全体をシングルクォート('')で囲む
python -m モジュール名 [引数] ...

引数を渡す

「import sys」を実行することでアクセス可能
sys.argv

対話モード (interactive mode)

一次プロンプト (primary prompt) (>>>)
二次プロンプト (secondary prompt) (...)

2.2. インタプリタとその環境

デフォルトでは、Python のソースコードは UTF-8 でエンコードされているものとして扱われる

3章 気楽な入門編   (出題数6問,15.00%)

組み込みデータ型(標準タイプ) (記載なし:全て読んだ後に再確認)  

変更不可 変更可 反復可 シーケンス マッピング データ
bool True,False
int 整数
float 浮動小数点数
complex 複素数
str 文字列
list
tuple
range
dict
set
bytes バイナリ
bytearray
file object

数値

演算子+-*/%()は他言語のイメージ通り

演算子.
>>> 17 / 3;      #除算 (python2では"//"と同じ結果
>>> 17 // 3;   # ***切り下げ除算***
>>> 5 *** 2;       #5の2乗
>>> 0%3            #0/3の余り  → 0 
3*3.72/1.5
対話モードでは、最後の表示した式は「_」(アンダースコア)に代入されている.
>>> price = 100.5
>>> tax = 10.5
>>> price * tax
>>> price + _      # 対話モードでは最後に表示した式を変数「_」に代入する
>>> _ = 10000      # 代入も出来てしまうが、リードオンリーとして扱うべき

変数に代入なしに使用するとエラー

文字列

>>> 'doesn\'t'     #エスケープ
>>> "doesn't"      #ダブルクォートで囲む
>>> s = 'First\nSecond'
>>> print(s)
>>> print(r'C:\some\name')   #raw文字列
その他(記載外).
>>> a = 'Py' 
>>> b = 'thon'
>>> c = 'Jython'
>>> a = b = c  # 多重代入
>>> a              # 最後の変数がすべてに適用される
'Jython'
>>> b
'Jython'
>>> c
'Jython'
トリプルクォート(ダブルクォーテーション、又はシングルクォーテーション)で改行がそのままで扱える.
>>> '''aaa                    # 例
... bbb
... ccc
... '''
'aaa\nbbb\nccc\n'

>>> print("""\          #複数行1
... Usage: ls
... -r
... -h
... """)
>>> print('''\          #複数行2
... Usage: ls
... -r
... -h
... ''')

文字列結合は基本的には+を使用する。(スペースも可能だが、変数同士・文字列同士以外ではエラー)
※試験とは多分関係ないが、ベストプラクティスは別にあるとのこと(joinメソッド、文字列フォーマット)

文字列結合.
>>> word = 'python'
>>> word2 = 'ium'
>>> 3 * 'un' + 'ium'           #繰り返し
'unununium'
>>> 'Py' + 'thon'        # 文字は+,スペースいずれも結合可能
'Python'
>>> 'Py' 'thon'
'Python'
>>> word 'ium'          # スペースでは変数と文字は結合不可
  File "<stdin>", line 1
    word 'ium'
             ^
SyntaxError: invalid syntax
>>> word word2           # スペースでは変数同士での結合は不可
  File "<stdin>", line 1
    word word2
             ^
SyntaxError: invalid syntax
>>> word + word2         # 変数同士、変数と文字の結合は+を使う
'pythonium'
変数文字列操作(インデックス指定).
>>> word = 'python'
>>> word[2]           #***0が最初の文字***
't'
>>> word[-2]     #***-1が最後の文字***
'o'

スライシングのスライシング
> 文字列[開始インデックス:終了インデックス:ステップ数]

インデクスが文字と文字の間(between)を指し、最初の文字の左端が0になっている.
 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
 0   1   2   3   4   5   6
-6  -5  -4  -3  -2  -1
変数文字列操作(スライシング(切取)指定).
>>> word = 'python'
>>> word[0:2]   # 最初の文字を含むが最後の文字を含まない
'py'
>>> word[2:5]   # 最初の文字を含むが最後の文字を含まない
'tho'
>>> word[:2]       #開始:省略時は0
'py'
>>> word[-2:]            #終了:省略時は文字列のサイズ(最後の文字まで)
'on'
>>> word[:-2]            #開始:省略時は0、 
'pyth'
>>> word[0:10:2]        # ステップ数も指定  ※本には記載なかったが模擬試験では出題
'pto'
>>> word[:2] + word[2:]  # 文字列と等価になる
'python'
変数文字列操作(範囲外指定).
>>> word[42]   # インデックス指定はNG
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: string index out of range
>>> word[4:42]   # スライシング指定はOK
'on'
変数文字列操作(文字列の変更).
>>> word[0] = 'J'   # Pythonの文字列は改変できない =変更不能体(immutable)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> 'J' + word[1:]  # 新しい文字列を生成する必要がある
'Jython'
変数文字列操作(文字列の長さ).
>>> word = 'dive\ninto\ncode\t'
>>> print(len(word))
15                                  #  制御文字は1文字にカウント
>>> d = 'xxxxDIVExxxxDIVExxxxDIVE'
>>> print(d.replace('DIVE', 'CODE', 1))
xxxxCODExxxxDIVExxxxDIVE           # 1番目の値のみ置き換え
>>> d
'xxxxDIVExxxxDIVExxxxDIVE'     # 元の文字列の変更はなし
リスト.
>>> squares = [1,4,9,16,25]
>>> squares
[1, 4, 9, 16, 25]
>>> squares[0]
1
>>> squares[2]
9
>>> squares[-1]
25
>>> squares[-3:]
[9, 16, 25]
>>> squares[:]
[1, 4, 9, 16, 25]
>>> squares[::]
[1, 4, 9, 16, 25]
>>> squares[:::]
  File "<stdin>", line 1
    squares[:::]
              ^
SyntaxError: invalid syntax
リストの連結.
>>> squares + [ 100, 1001 ]
[1, 4, 9, 16, 25, 100, 1001]
>>> squares2 = [ 8001, 8002 ]
>>> squares + squares2
[1, 4, 9, 16, 25, 8001, 8002]  # リストの値は変わらない
リストは変更可能体(mutable).
>>> squares[1] = 40000
>>> squares
[1, 40000, 9, 16, 25]
>>> squares.append(216)           # append()メソッド
>>> squares.append(7**3)
>>> squares
[1, 40000, 9, 16, 25, 216, 343]   # リストの末尾に追加

>>> letters = ['a','b','c','d','e','f','g']  # スライシングへの代入も可能
>>> letters
['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> letters[2:5] = ['C','D','E']
>>> letters
['a', 'b', 'C', 'D', 'E', 'f', 'g']
>>> letters[2:5] = []
>>> letters
['a', 'b', 'f', 'g']
>>> letters[:] = []
>>> letters
[]

4章 制御構造ツール   (9問,22.50%)

4.1 if文

4.2 for文

4.3 range()関数

for i in range(s):
print(i)

range(10) # 0から1ステップずつであれば、第1、3引数省略可能
range(5, 10) # 1ステップずつであれば、第3引数省略可能
range(0, 10, 3) # 0から10まで3ステップずつ

>>> print(range(10))  # (注意)値の連番が表示されるわけではない
range(0, 10)

4.4. break文とcontinue文、ループにおけるelse節

・break文とcontinue文はC言語と同様、それぞれループを抜けるのと、ループの残りを飛ばして次の反復にいく。
・ループにおけるelse節は、if文のそれよりもtry文のそれに似ている。
tyr文では例外が起きなかったときに、ループではbreakが起きなかったときに実行される。

4.5. pass文

・何もしない。構文的にエラーとなってしまう場合に使う。

最小クラスを作る場合.
>>> class MyEmptyClass:
...     pass
新しいコードを書いている時の関数や条件文に具体的なコードを記載しない場合.
>>> def initlog(*args):
...     pass

4.6. 関数の定義    ★★

4.7. さらに関数定義について  ★★

4.7.1. 引数値のデフォルト
 もっとも便利なのは、一つ以上の引数に対してデフォルトの値を指定する形式

def ask_default(a, b, c=100):  # 第3引数省略時cに100が設定される

後に続く関数呼び出しで関数に渡されている引数を累積.
>>> def f(a, L=[]):
...     L.append(a)
...     return L
...
>>> print(f(1))
[1]
>>> print(f(2))
[1, 2]
>>> print(f(3))
[1, 2, 3]

4.7.2. キーワード引数
 関数を「キーワード=値」という形式も取れる。
 関数をコールするときは、必ず位置引数が先でキーワード引数を後にしなければならない。

>>> def fugafuga(title,content = 'default_content', number = 4):
...     print(title, end=' ')
...     print(content, end=' ')
...     print(number)
...
...
>>> fugafuga(title = 'title_default', content = 'None', number = 5)
title_default None 5
>>> fugafuga(title = 'title_default', number = 5)  # キーワード引数の省略可能(途中の引数の省略も可能)
title_default default_content 5
>>> fugafuga(1000)                               # 位置引数も可能(途中の引数の省略は不可)
1000 default_content 4

4.7.3. 任意引数リスト
 最も使うことの少ない選択肢として、関数が任意の個数の引数で呼び出せるよう指定する方法

>>> def write_multiple_items(file, separator, *args):
...     file.write(separator.join(args))
>>> concat("earth", "mars", "venus")
'earth/mars/venus'
>>> concat("earth", "mars", "venus", sep=".")
'earth.mars.venus'
>>> def dive_into_code(teacher, *mentor):
...     print(teacher)
...     print(mentor)
...
>>> dive_into_code('Noro', 'Nakao', 'Miyaoka')
Noro                      # 第1引数箇所
('Nakao', 'Miyaoka')      # 第2引数箇所以降

4.7.4. 引数リストのアンパック

4.7.5. ラムダ式

4.7.6. 引数リストのアンパック
ドキュメンテーション文字列

4.8. 幕間つなぎ:コーディングスタイル

Python には、ほとんどのプロジェクトが守っているスタイルガイドとして PEP 8 がある。

下記要点
・インデントには空白4つを使い、タブは使わないこと。
・空白4つは(深くネストできる)小さいインデントと(読み易い)大きいインデントのちょうど中間に当たります。タブは混乱の元なので排除するのがよい。
・ソースコードの幅が 79文字を越えないように行を折り返すこと。
 こうすることで小型ディスプレイのユーザを助け、大型ディスプレイではコードを並べることもできるようになる。
・関数やクラスや関数内の大きめのコードブロックの区切りに空行を使うこと。
・可能なら、コメントは行に独立で書くこと。
・docstring を使うこと。
・演算子の前後とコンマの後には空白を入れ、括弧類のすぐ内側には空白を入れないこと: a = f(1, 2) + g(3, 4)。
・クラスや関数に一貫性のある名前を付けること。慣習ではCamelCaseをクラス名に使い、lower_case_with_underscores を関数名やメソッド名に使う。常にself をメソッドの第1引数の名前として使うこと。
・国際的な環境でつかうつもりのコードでは、風変りなエンコーディングは使わないこと。どんな場合でも、Python のデフォルト UTF-8 またはプレーン ASCII が最も上手くいきます。
・同様に、ほんの少しでも他の言語を話す人がコードを読んだりメンテナンスする可能性があるのであれば、非 ASCII 文字も識別子に使うべきではありません。

5章 データ構造   (7問,17.50%)

###リストについての補足

リストのメソッド
append(x)
extend(L)
insert(i,x)
remove(x)
pop([i]) リスト中の指定された位置にある要素をリストから削除して、その要素を返す。省略時はリストの末尾の要素が対象。
clear() del a[:] と等価
index(x)
countx(x)
list.sort(key=None,reverse=False)
list.reverse()
list.copy()  リストの浅い (shallow) コピーを返す。a[:] と等価。
list.count(x) リストに含まれるxの件数

>>> key = ['001','002','003','002','005','006','003','009']
>>> print(key.count('001'),key.count('002'),key.count('003'))
1 2 2
>>> key.reverse()
>>> key
['009', '003', '006', '005', '002', '003', '002', '001']
>>> key.sort()
>>> key
['001', '002', '002', '003', '003', '005', '006', '009']
>>> key.append('010')
>>> key
['001', '002', '002', '003', '003', '005', '006', '009', '010']
>>> key.insert(2,'020')
>>> key
['001', '002', '020', '002', '003', '003', '005', '006', '009', '010']
>>> key.extend(key)
>>> key
['001', '002', '020', '002', '003', '003', '005', '006', '009', '010', '001', '002', '020', '002', '003', '003', '005', '006', '009', '010']:

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

リスト型メソッド(popとappend)によりリストをスタックとして使える.
>>> stack = [3, 4, 5]
>>> stack.append(6)
>>> stack.append(7)
>>> stack
[3, 4, 5, 6, 7]
>>> stack.pop()
7
>>> stack.pop()
6
>>> stack
[3, 4, 5]

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

リストをキューとして使うことも可能だが、リストのメソッドでは効率的にでない。
追加(append)や取り出し(pop)をリストの末尾に対して行うと速いが、
挿入(insert)や取り出し(pop)をリストの先頭に対して行うと遅くなる。(他の要素をひとつずつずらす必要があるため)。
collections.dequeを使用する。
※キュー (queue):最初に追加した要素を最初に取り出す (「first-in, first-out」)。

>>> from collections import deque
>>> queue = deque(["Eric", "John", "Michael"])
>>> queue.append("Terry")
>>> queue.append("Graham")
>>> queue.popleft()
'Eric'
>>> queue.popleft()
'John'
>>> queue
deque(['Michael', 'Terry', 'Graham'])

リスト内包  ★後日見直し★

>>> squares = []
>>> for x in range(10):
...     squares.append(x**2)
...
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

>>> squares = list(map(lambda x: x**2, range(10)))  # 上記と同じ
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> squares = [x**2 for x in range(10)]              # 上記と同じ:リストの内包
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
>>> #  上記と等価
>>> combs = []
>>> for x in [1,2,3]:
...      for y in [3,1,4]:
...          if x != y:
...              combs.append((x, y))   # 式がタプルの場合は、タプルに円括弧が必:要
...
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
>>> [[x, y] for x in [1,2,3] for y in [3,1,4] if x != y]
[[1, 3], [1, 4], [2, 3], [2, 1], [2, 4], [3, 1], [3, 4]]
>>> vec = [-4, -2, 0, 2, 4]
>>> [x*2 for x in vec]
[-8, -4, 0, 4, 8]
>>> [x for x in vec if x >= 0]
[0, 2, 4]
>>> [abs(x) for x in vec]
[4, 2, 0, 2, 4]
>>> freshfruit = ['  banana', '  loganberry ', 'passion fruit  ']
>>> [weapon.strip() for weapon in freshfruit]
['banana', 'loganberry', 'passion fruit']
>>> [(x, x**2) for x in range(6)]      # 2値のタプルのリストを生成
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
>>> [x, x**2 for x in range(6)]      # タプルを○かっこで囲わないとエラー
  File "<stdin>", line 1
    [x, x**2 for x in range(6)]
               ^
SyntaxError: invalid syntax
>>> vec = [[1,2,3], [4,5,6], [7,8,9]]    # リストを平滑化(1次元化):forを2つ使う
>>> [num for elem in vec for num in elem]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> from math import pi
>>> [str(round(pi, i)) for i in range(1, 6)]
['3.1', '3.14', '3.142', '3.1416', '3.14159']

入れ子のリスト内包

matrixの行と列を入れ替える.
>>> matrix = [         # matrix = [[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12],]
...     [1, 2, 3, 4],
...     [5, 6, 7, 8],
...     [9, 10, 11, 12],
... ]
>>> [[row[i] for row in matrix] for i in range(4)]   # 内包表記
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

 # 下記と等価
>>> transposed = []
>>> for i in range(4):
...     transposed.append([row[i] for row in matrix])
...
>>> transposed
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

 # 下記とも等価
>>> transposed = []
>>> for i in range(4):
...     transposed_row = []
...     for row in matrix:
...         transposed_row.append(row[i])
...     transposed.append(transposed_row)
...
>>> transposed
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

実際には複雑な流れの式よりも組み込み関数のzip()を使う方が良い。
zip() 関数 …複数のイテラブルオブジェクト(リストやタプルなど)の要素をまとめる関数

>>> list(zip(*matrix))
[(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]
参考:追加確認.
>>> [row[i] for row in matrix3]  # 
[4, 8, 12]
>>> [i for row in matrix3]     # 
[3, 3, 3]
>>> matrix3
[[1, 2, 3, 4, 99], [5, 6, 7, 8, 91], [9, 10, 11, 12, 92, 93]]
>>> [[row[i] for row in matrix3] for i in range(5)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12], [99, 91, 92]]
>>> [[row[i] for row in matrix3] for i in range(6)]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <listcomp>
  File "<stdin>", line 1, in <listcomp>
IndexError: list index out of range

for a,b,c in zip(A,B,C) # 複数のシーケンスのイテレート

参考:zip().
>>> names = ['Alice', 'Bob', 'Charlie']
>>> ages = [24, 50, 18]
>>> for name, age in zip(names, ages):
...     print(name, age)
...
Alice 24
Bob 50
Charlie 18

del文

>>> a = [-1, 1, 66.25, 333, 333, 1234.5]
>>> del a[0]
>>> a
[1, 66.25, 333, 333, 1234.5]
>>> del a[2:4]
>>> a
[1, 66.25, 1234.5]
>>> del a[:]  # 全ての値を削除
>>> a
[]
>>> del a     # 変数全体の削除
>>> a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined

タプルとシーケンス

・シーケンス (sequence) データ型 : — list, tuple, rangeなど
・タプル(tuple)
タプルを書くときは必ずしも丸括弧で囲まなくてもいい
(タプルが大きな式の一部だった場合は) 丸括弧が必要な場合もある
タプルの要素を代入することはできない。不変型 (immutable) 。
タプルにリストのような変更可能型を含めることはできる。
要素はアンパック操作やインデックス(あるいはnamedtuplesの場合は属性)でアクセスすることが多い

タプル.
>>> t = 12345, 54332, 'hello!'
>>> t
(12345, 54332, 'hello!')
>>> t[0]
12345
>>> u = t, (1, 2, 3, 4, 5)
>>> u           # タプルは入れ子にできる
((12345, 54332, 'hello!'), (1, 2, 3, 4, 5))
>>> t[0] = 88888     # タプルは変更不能
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
パック・アンパック.
>>> t = 12345, 54321, 'hello!'    # タプルのパック (tuple packing)
>>> x, y, z = t                   # シーケンスのアンパック (sequence unpacking)
>>> x
12345
>>> y
54321
>>> z
'hello!'
タプルのメソッド.
>>> key0 = ('001','002','003','002','005','006','003','009')
>>> key0.count('002')
2
>>> key0.append('099')   # 変更するメソッドは不可
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>

AttributeError: 'tuple' object has no attribute 'append'

集合(set)

重複する要素をもたない、順序づけられていない要素の集まり

基本的な用途としては存在判定、重複エントリの排除
和 (union)、積 (intersection)、差 (difference)、対称差 (symmetric difference)といった数学的な演算もサポート

>>> basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
>>> print(basket)
{'banana', 'apple', 'orange', 'pear'}
>>> 'orange' in basket
True
>>> 'crabgrass' in basket
False
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a
{'c', 'd', 'a', 'b', 'r'}       # 'abracadabra'から重複した要素が削除'abrcd'
(参考2.7)set(['a', 'r', 'b', 'c', 'd'])
>>> a - b               # 差集合(differenceメソッドも同じ)
{'d', 'r', 'b'}
>>> a | b                           # 和集合(unionメソッドも同じ)
{'c', 'z', 'm', 'l', 'd', 'a', 'b', 'r'}
>>> a & b                           # 積集合(intersectionメソッドも同じ):aにもbにもう一度存在する文字
{'c', 'a'}
>>> a ^ b                          # 排他的論理和集合(symmetric_differenceメソッドも同じ):aまたはbにある共通しない文字
{'d', 'z', 'm', 'r', 'b', 'l'}
set内包もサポート.
>>> a = {x for x in 'abracadabra' if x not in 'abc'}
>>> a
{'r', 'd'}

(範囲外)
集合(set)に要素の追加   myset.add(x)
集合(set)より要素の削除  myset.remove(x)
list型からset型を作る

>>> mylist = [2, 1, 3, 1]
>>> myset = set(mylist)
>>> print(myset)
{1, 2, 3}

ディクショナリ (辞書型 (dictionary))

キー(一意)と値が集まった順序を持たない集合

キー(key): 値(value)
何らかの変更不能な型のみキーとすることが可能
タプルは、文字列、数値、その他のタプルのみを含む場合はキーにすることができる。リストは出来ない。)
※他の言語にも 「連想記憶 (associated memory)」 や 「連想配列 (associative array)」 という名前で存在

>>> tel = {'jack': 4098, 'sape': 4139}
>>> tel['guido'] = 4127
>>> tel
{'jack': 4098, 'sape': 4139, 'guido': 4127}
>>> tel['jack']
4098
>>> del tel['sape']                  # 削除 (未存在時はエラー)
>>> tel
{'jack': 4098, 'guido': 4127}             # 'sape'が削除されている
>>> tel['irv'] = 4127                                # 'irv'を追加
>>> tel
{'jack': 4098, 'guido': 4127, 'irv': 4127}        # 'irv'の位置:3系(3.6.8)での結果。
(参考) {'jack': 4098, 'irv': 4127, 'guido': 4127}  # 'irv'の位置:本,Webはこちら。2系(2.7.5)で実施したらこちらの結果となった ※順序を持たないため気にしなくてよい
>>> tel['irv'] = 9999                                # 値の編集
>>> tel
{'jack': 4098, 'guido': 4127, 'irv': 9999}               
>>> list(tel.keys())
['jack', 'guido', 'irv']
>>> sorted(tel.keys())
['guido', 'irv', 'jack']
>>> 'guido' in tel              # 存在チェック
True
>>> 'jack' not in tel
False
dict()コンストラクタは、キーと値のペアのタプルを含むリストから辞書を生成.
>>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
{'sape': 4139, 'guido': 4127, 'jack': 4098}      # 3系(3.6.8)での実行結果
(参考){'sape': 4139, 'jack': 4098, 'guido': 4127}  # 2系(2.7.5)での実行結果
キーが単純な文字列の場合、キーワード引数を使って定義し辞書を生成.
>>> dict(sape=4139, guido=4127, jack=4098)
{'sape': 4139, 'guido': 4127, 'jack': 4098}      # 3系(3.6.8)での実行結果
(参考){'sape': 4139, 'jack': 4098, 'guido': 4127}  # 2系(2.7.5)での実行結果
辞書内包表現を使って、任意のキーと値のペアから辞書を生成.
>>> {x: x**2 for x in (2, 4, 6)}
{2: 4, 4: 16, 6: 36}
>>>dic = {'Noro': 1, 'Nakao': 2, 'Miyaoka': 3}
>>>dic['Miyaoka'] += 1
>>>print(dic)
{'Noro': 1, 'Nakao': 2, 'Miyaoka': 4}      #1加算!!

ディクショナリのメソッド
update()
copy()
items()
values()
del
clear()

ループのテクニック

 辞書に対してループを行う際、items()メソッドを使うと、キーとそれに対応する値を同時に取り出せる.
>>> knights = {'gallahad': 'the pure', 'robin': 'the brave'}
>>> for k, v in knights.items():
...     print(k, v)
... 
gallahad the pure
robin the brave
シーケンスにわたるループを行う際、enumerate()関数を使うと、要素のインデックスと要素を同時に取り出せる.
>>> for i, v in enumerate(['tic', 'tac', 'toe']):
...     print(i, v)
...
(0, 'tic')   # 要素のインデックス、値
(1, 'tac')
(2, 'toe')
二つまたはそれ以上のシーケンス型を同時にループするため、関数zip()を使って各要素をひと組みにする.
>>> questions = ['name', 'quest', 'favorite color']
>>> answers = ['lancelot', 'the holy grail', 'blue']
>>> for q, a in zip(questions, answers):
...     print('What is your {0}?  It is {1}.'.format(q, a))
...
What is your name?  It is lancelot.
What is your quest?  It is the holy grail.
What is your favorite color?  It is blue.
シーケンスの範囲を順方向に指定し、次いで関数reversed()を呼び出す.
>>> for i in reversed(range(1, 10, 2)):
...     print(i)
...
9
7
5
3
1
シーケンスをソートされた順序でループ:sorted()関数を使う。(元の配列を変更せず、ソート済みの新たな配列を返す).
>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
>>> for f in sorted(set(basket)):
...     print(f)
...
apple
banana
orange
pear
リストの変更より新しいリストを作るほうが簡単で安全なケースもある.
>>> import math
>>> raw_data = [56.2, float('NaN'), 51.7, 55.3, 52.5, float('NaN'), 47.8]
>>> filtered_data = []
>>> for value in raw_data:
...     if not math.isnan(value):
...         filtered_data.append(value)
...
>>> filtered_data
[56.2, 51.7, 55.3, 52.5, 47.8]

5.7 条件についての補足

while や if 文で使った条件 (condition) について、値の比較だけでなく、他の演算子もある
・比較演算子 in および not in :ある値があるシーケンス中に存在するか (または存在しないか) ※既出
・演算子 is および is not :二つのオブジェクトが実際に同じオブジェクトであるかどうか
   リストのような変更可能なオブジェクトにだけ意味がある
   ※但し、isは、is None のように、シングルトンの変更不能オブジェクトとの比較に用いる場合もある(webのみの記載)
・全ての比較演算子は同じ優先順位を持っており、ともに数値演算子よりも低い優先順位
・比較の連鎖 :a < b == c は、 a が b より小さく、かつ b と c が等しいかどうかをテスト
・ブール演算子 and や or で比較演算を組み合わせることができる。否定はnot。優先順位は他の比較演算子より低い。
・ブール演算子 and や or はよく短絡演算子と呼ばれる。: 演算子の引数は左から右へと順に評価され、結果が確定した時点で評価を止める。

>>> string1, string2, string3 = '', 'Trondheim', 'Hammer Dance'
>>> non_null = string1 or string2 or string3
>>> non_null
'Trondheim'

・Python では、C 言語と違い、式の内部で代入を行えないので注意
  C:  if(a=1)==1

5.8 シーケンスの比較、その他の型の比較

・シーケンスオブジェクトは同じシーケンス型を持つオブジェクトと比較できる。
・モジュールの中では、(文字列の) モジュール名をグローバル変数 name で取得可能
(比較方法)    ★★
・辞書的順序にて比較
・二つのシーケンスの全ての要素の比較結果が等しくなれば、シーケンスは等しいとみなされる。
・片方のシーケンスがもう一方の先頭部分にあたる部分シーケンスならば、短い方のシーケンスが小さいシーケンスとみなされる。

>>> (1, 2, 3)              < (1, 2, 4)
True
>>> [1, 2, 3]              < [1, 2, 4]
True
>>> (1, 2, 3, 4)           < (1, 2, 4)
True
>>> (1, 2)                 < (1, 2, -1)
True
>>> 'ABC' < 'C' < 'Pascal' < 'Python'         # 辞書順
True
>>> (1, 2, 3)             == (1.0, 2.0, 3.0)     # 0 と 0.0 は等価
True
>>> (1, 2, ('aa', 'ab'))   < (1, 2, ('abc', 'a'), 4)
True

(メモ)文字の比較:辞書順って規格が不明だったので少し調べたがすぐにはわからなかったので動きだけ調べてみた。
少なくともassciiコードの順番にはなっているよう。

>>> 'C' < 'c'   # 'C':0x43、'c':0x63
True
>>> 'c' < 'C'
False
>>> 'c' < 'c'
False
>>> 'C' < 'C'
False
>>> '(' < ')'   # '(':0x28、')':0x29
True
>>> ')' < '('
False

・違う型のオブジェクト同士の比較は、それらのオブジェクトが適切な比較メソッドを提供しているのであれば可能だが、
適切な比較メソッドを提供していない場合は、インタープリターは TypeError 例外を発生
 (参考:Python2系) 比較的ない場合でも常にFalse となりエラーにはならない

文字列と数値、リストとタプルの比較はTypeError.
>>> 'ab' < 3                   # 文字列と数値.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'str' and 'int'
>>> (1,3,5) < [1,3,6]           # リストとタプル.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'tuple' and 'list'

6章 モジュール   (2問,5.00%)

・Python では定義をファイルに書いておき、スクリプトの中やインタプリタの対話インスタンス上で使う方法があり、このファイルを モジュール (module) と呼ぶ。
・モジュールにある定義は、他のモジュールや main モジュールにimport (取り込み) が可能。

>>> import fibo
>>> fibo.fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377

・モジュールは Python の定義や文が入ったファイル。ファイル名は「モジュール名+.py」
・関数を頻繁に使いたいときはローカル変数に代入可能

>>> import fibo
>>> fib = fibo.fib   # ローカル変数に代入可能 (モジュール定義は省略)
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377

さらにモジュールについて

・モジュールには、関数定義に加えて実行文を入れることができる。(モジュールを初期化するためのもの)
 れらの実行文は、インポート文の中で 最初に モジュール名が見つかったときにだけ実行される。
・各々のモジュールは、自分のプライベートなシンボルテーブルを持ち、モジュールで定義されている関数はこのテーブルをグローバルなシンボルテーブルとして使う。
・グローバルな変数をモジュールで使うことができる。
・モジュールが他のモジュールを import することもできる。
・import 文は全てモジュールの先頭に置くが、慣習であって必須ではない。
・import されたモジュール名は import を行っているモジュールのグローバルなシンボルテーブルに置かれる。
・import 文には、あるモジュール内の名前を、import を実行しているモジュールのシンボルテーブル内に直接取り込むという変型もある

import <モジュール名>
from <モジュール名> import <関数・変数名>

>>> from fibo import fib, fib2
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377

・モジュールで定義されている名前を全て import するという変型もある
 ※アンダースコア (_) で始まるものを除いてすべての名前をインポートする
 ※この書き方は基本的には推奨されない(未知の名前が定義済みの名前を上書きしてしまう可能性があるため)

>>> from fibo import *
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377

・importlib.reload()関数の使用 (3.4以降、3.3まではimp.reload())
実行効率の理由により、各モジュールはインタープリタの 1 セッションごとに 1 回しかimportされないため、
モジュールを修正しすぐにテストしたい場合に再読み込みをする。

モジュールをスクリプトとして実行

・「python fibo.py 」とスクリプト実行すると、namemain が設定される。
・下記のコードを追加することで、スクリプトとして使用可能になる。(importも可能)
 ※スクリプトとしての実行でなく、「import fibo」と使用した場合は実行されない

if __name__ == "__main__":
    import sys
    fib(int(sys.argv[1]))

モジュールの検索パス

spam という名前のモジュールをインポートするときの順番
1.ビルトインモジュール
2.spam.py という名前のファイルを sys.path にあるディレクトリのリストから探す
  (sys.path は以下の場所に初期化)※初期化後、sys.pathはプログラムにて修正可能
  2.1.入力されたスクリプトのあるディレクトリ (あるいはファイルが指定されなかったときはカレントディレクトリ)。
  2.2.PYTHONPATH (ディレクトリ名のリスト。シェル変数の PATH と同じ構文)。
  2.3.インストールごとのデフォルト。
     ※シンボリックリンクを含むディレクトリはモジュール検索パスに追加 されない。

「コンパイル済」Python ファイル

モジュールの読み込み高速化のため、コンパイル済みの各モジュールを「 pycache 」ディレクトリの 「 module.version.pyc 」ファイルとしてキャッシュ
※Python の異なる複数のリリースやバージョンのコンパイル済みモジュールが共存可能

# ll -R
drwxr-xr-x 2 root root  33  1月  1 08:31 __pycache__
-rw-r--r-- 1 root root 376  1月  1 08:48 fibo.py

./__pycache__:
-rw-r--r-- 1 root root 503  1月  1 08:31 fibo.cpython-36.pyc

・Python はソースの変更日時をコンパイル済みのものと比較し、コンパイル済みのものが最新でなくなり再コンパイルが必要になっていないかを自動的に確認
・コンパイル済みモジュールはプラットフォーム非依存なため、アーキテクチャの異なるシステム間で同一のライブラリを共有可能
・キャッシュのチェックを行わない2つのケース
 > コマンドラインから直接モジュールが読み込まれた場合で、常に再コンパイル
 > ソース・モジュールのない場合
 ※コンパイル済みのもののみの配布をサポートするには、コンパイル済みモジュールは
ソース・ディレクトリになくてはならず、ソース・ディレクトリにソース・モジュールがあってはならない。
・コンパイル済みモジュールのサイズを小さくするため、Python コマンドに -O(assert ステートメントを除去) または -OO(assert ステートメントと doc 文字列を除去)スイッチを使う
 ※除去されるものに依存するプログラムがある可能性があるため、理解した上で使用する
・.pyc ファイルや .pyo ファイルから読み出されたとしても、プログラムは .py ファイルから読み出されたときより何ら高速に動作するわけではありません。.pyc ファイルで高速化されるのは、読み込みにかかる時間だけ
・compileallモジュールを使ってディレクトリ内の全てのモジュールに対して .pyc ファイルを作ることができる。
・フローチャートなど、この処理に関する詳細が PEP 3147 に記載。

標準モジュール

winreg モジュール   Windows システムでのみ提供
sys.ps1 と sys.ps2 という変数  一次プロンプトと二次プロンプトに表示する文字列を定義

sys.pathは環境変数PYTHONPATHから得たデフォルトパスに、PYTHONPATHが設定されていなければ組み込みのデフォルト値に設定.
>>> import sys
>>> sys.path.append('/ufs/guido/lib/python')

dir() 関数

モジュールが定義している名前を確認することができる。ソートされた文字列のリストを返す。

>>> import fibo, sys
>>> dir(fibo)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'fib', 'fib2']
>>> dir(sys)
['__displayhook__', '__doc__', '__excepthook__', '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__', (省略)
引数がなければ、dir()は現在定義している名前を列挙.
>>> a = [1, 2, 3, 4, 5]
>>> fib = fibo.fib
>>> dir()            # 引数なし
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'fib', 'fibo', 'sys']

組込みの関数や変数の名前のリストは標準モジュールbuiltinsを使用 ※dir()ではリストされない

>>> import builtins
>>> dir(builtins)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError',(省略)

パッケージ (package)

「ドット区切モジュール名」 を使ってPythonのモジュールを構築する方法

・モジュール名 A.B  → AというパッケージのサブモジュールBを表す
・複数モジュールからなるパッケージの著者が、互いのモジュール名について心配しなくても済むようになる
・あるディレクトリを、パッケージが入ったディレクトリとしてPythonに扱わせるには、ファイル__init__.pyが必要
・最も簡単なケースでは__init__.pyはただの空ファイルで構わないが、init.pyではパッケージのための初期化コードを実行したり、__all__変数を設定してもかまわない

パッケージから個々のモジュールのimport(ケース1).
>>> import sound.effects.echo
>>> sound.effects.echo.echofilter(input, output, delay=0.7, atten=4) # 完全な名前で参照が必要
パッケージから個々のモジュールのimport(ケース2).
>>> from sound.effects import echo
>>> echo.echofilter(input, output, delay=0.7, atten=4)     # パッケージ名なしで利用可能
パッケージから個々のモジュールのimport(ケース3).
from sound.effects.echo import echofilter
echofilter(input, output, delay=0.7, atten=4)  # メソッドを直接利用可能

・「from package import item 」の構文使用時
item はパッケージpackageのサブモジュール(またはサブパッケージ) でもよいし、
 関数やクラス、変数など、 packageで定義された他の名前でもよい
import文はまず、item がパッケージ内で定義されているかどうか調べます。
定義されていなければ、 item はモジュール名であると仮定して、モジュールをロードしようと試みます。
もしモジュールが見つからなければ、 ImportError が送出される

・「import item.subitem.subsubitem 」の構文使用時
 最後のsubsubitemを除く各要素はパッケージでなければならない

パッケージから * を import する

パッケージの作者にパッケージの索引を明示的に提供させる

「from sound.effects import * 」

パッケージ内の相互参照

複数のディレクトリにまたがるパッケージ

特別な属性として path をサポート
__path__属性は、パッケージの init.py 中のコードが実行されるよりも前に、
init.py の収められているディレクトリ名の入ったリストになるよう初期化される

7章 入出力 |1 |2.50%|

手の込んだ出力フォーマット

・値を出力する方法:
 > 式文 (expression statement)
 > print() 関数
 > ファイルオブジェクトの write() メソッド

・標準出力を表すファイルは sys.stdout で参照可能
・出力のフォーマット方法
 > 文字列スライシングと連結操作を利用し、文字列処理をすべてじぶんでやる
 > str.formatメソッドを使用
 > stringモジュールのTemplateクラスを使用
  値を文字列への変換方法:値を repr() か str() 関数に渡す。

・str() 関数は値の人間に読める表現を返すためのもので、
 repr() 関数はインタープリタに読める (あるいは同値となる構文がない場合は必ず SyntaxError になるような) 表現を返すためのもの
人間が読むのに適した特定の表現を持たないオブジェクトにおいては、 str() は repr() と同じ値を返す。

>>> s = 'Hello, world.'
>>> str(s)
'Hello, world.'
>>> repr(s)
"'Hello, world.'"
>>> str(1/7)
'0.14285714285714285'
>>> repr(1/7)
'0.14285714285714285'
>>> x = 10 * 3.25
>>> y = 200 * 200
>>> s = 'The value of x is ' + repr(x) + ', and y is ' + repr(y) + '...'
>>> print(s)
The value of x is 32.5, and y is 40000...
>>> str(s)
'The value of x is 32.5, and y is 40000...'
>>> repr(s)
"'The value of x is 32.5, and y is 40000...'"
>>> hello = 'hello, world\n'
>>> hellos = repr(hello)
>>> print(hellos)
'hello, world\n'
>>> str((x, y, ('spam', 'eggs')))
"(32.5, 40000, ('spam', 'eggs'))"
>>> repr((x, y, ('spam', 'eggs')))
"(32.5, 40000, ('spam', 'eggs'))"
2種類の方法で平方と立方の表を書く.
>>> for x in range(1, 11):
...     print(repr(x).rjust(2), repr(x*x).rjust(3), end=' ')
...     print(repr(x*x*x).rjust(4))
...
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000
>>> for x in range(1, 11):
...     print('{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x))
...
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000

str.rjust(width[, fillchar])メソッド  ・・・width の長さをもつ右寄せした文字列を返す。fillchar指定時は指定された文字で埋める。
str.ljust(width[, fillchar])メソッド ・・・width の長さをもつ左寄せした文字列を返す。fillchar指定時は指定された文字で埋める。
 文字を切り詰めを行いたいのなら、スライスを使用し、x.ljust(n)[:n]とする。丸めるならround()。
str.center(width[, fillchar])メソッド ・・・width の長さをもつ中央寄せされた文字列を返す。fillchar指定時は指定された文字で埋める。
str.zfill()メソッド   ・・・数値文字列の左側をゼロ詰めする

>>> '12'.zfill(5)
'00012'
>>> '-3.14'.zfill(7)
'-003.14'
>>> '3.14159265359'.zfill(5)
'3.14159265359'

str.format()メソッド

括弧とその中の文字(これをフォーマットフィールドと呼ぶ).
>>> print('We are the {} who say "{}!"'.format('knights', 'Ni'))
We are the knights who say "Ni!"
括弧の中の数字はstr.format()メソッドに渡されたオブジェクトの位置を表すのに使える.
>>> print('{0} and {1}'.format('spam', 'eggs'))
spam and eggs
>>> print('{1} and {0}'.format('spam', 'eggs'))
eggs and spam
str.format()メソッドにキーワード引数が渡された場合、その値はキーワード引数の名前によって参照される.
>>> print('This {food} is {adjective}.'.format(
...       food='spam', adjective='absolutely horrible'))
This spam is absolutely horrible.
順序引数とキーワード引数を組み合せも可能.
>>> print('The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred',other='Georg'))
The story of Bill, Manfred, and Georg.
'!a'(ascii()を適応)や'!s'(str()を適応)や'!r'(repr()を適応)を使って、値をフォーマットする前に変換可能.
>>> contents = 'eels'
>>> print('My hovercraft is full of {}.'.format(contents))
My hovercraft is full of eels.
>>> print('My hovercraft is full of {!r}.'.format(contents))
My hovercraft is full of 'eels'.
フォーマット指定子によって値がどうフォーマットされるかを制御可能.
>>> import math
>>> print('The value of PI is approximately {0:.3f}.'.format(math.pi))
The value of PI is approximately 3.142.
'の後ろに整数をつけると、そのフィールドの最低の文字幅を指定.
>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}
>>> for name, phone in table.items():
...     print('{0:10} ==> {1:10d}'.format(name, phone))
...
Sjoerd     ==>       4127
Jack       ==>       4098
Dcab       ==>       7678
辞書を引数に渡して、角括弧'[]'を使って辞書のキーを参照可能.
>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
>>> print('Jack: {0[Jack]:d}; Sjoerd: {0[Sjoerd]:d}; '
...       'Dcab: {0[Dcab]:d}'.format(table))
Jack: 4098; Sjoerd: 4127; Dcab: 8637678
 tableを『**』記法を使ってキーワード引数として渡す方法.
>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
>>> print('Jack: {Jack:d}; Sjoerd: {Sjoerd:d}; Dcab: {Dcab:d}'.format(**table))
Jack: 4098; Sjoerd: 4127; Dcab: 8637678

古い文字列書式設定方法

% 演算子を使って文字列書式設定

>>> import math
>>> print('The value of PI is approximately %5.3f.' % math.pi)
The value of PI is approximately 3.142.

ファイルの読み書き

openの第2引数: ※C言語のfopenと同じ

モード 動作 ファイルがある場合 ファイルがない場合
r (省略時) 読み出し専用 変化なし エラー
w 書き込み専用 サイズを0にする(上書き) 新規作成
a 追加書き込み専用 ファイルの最後に追加 新規作成
r+ 読み込みと書き込み 変化なし エラー
w+ 書き込みと読み込み サイズを0にする(上書き) 新規作成
a+ 読み込みと追加書き込み ファイルの最後に追加 新規作成

テキストモードとバイナリモード
・テキストモード (省略時) 
 改行コードを変換する
 改行コードをEOF(ファイルエンド)として扱う
・バイナリモード(b)  ・・・JPGやEXEのようなバイナリデータはこちらを指定する
 改行コードを変換しない
 改行コードをEOF(ファイルエンド)として扱わない
 指定方法:上記モードと組み合わせ 'rb','r+b'とする。(bは前後どちらでもよいが見るのはbが後ろ)

ファイルオープン.
f = open('workfile','wb')

ファイルオブジェクトのメソッド

readとreadline

f.read(size)にて読み込む.
f = open('workfile','w')
>>> f.read()
'123\n456\n'
f.read(size)にてsize分読み込む.
>>> f.read(5)
'123\n4'                    # 指定バイトの文字列を返す
>>> f.read(5)
'56\n'            # 指定バイトに達しない場合は存在する文字列だけを返す
>>> f.read(5)
''              # 末尾に達した場合は''を返す
readlineにて読み込む.
>>> f.readline()
'123\n'           # 1行ずつ返す
>>> f.readline()
'456\n'
>>> f.readline()
''              # 末尾に達した場合は''を返す
ファイルから複数行を読み取るには、ファイルオブジェクトに対してループを書く.
>>> f = open('workfile','r+')
>>> for line in f:
...     print(line, end='')
...
123
456

ファイルのすべての行をリスト形式で読み取りたいなら、list(f) や f.readlines() を使うことも可能

ファイル書き込み.
>>> f = open('workfile','r+')
>>> f.write('This is a test\n') # ファイル書き込み
15                              # 書き込まれた文字数が返される
>>> f.close()
>>> f = open('workfile','r+')  # 下記は確認
>>> f.read()
'This is a test\n'
>>> f.close()

オブジェクトの他の型は、書き込む前に変換する必要がある
文字列 (テキストモード) と bytes オブジェクト (バイナリーモード) のいずれか

>>> f = open('workfile','r+')
>>> value = ('the answer', 42)
>>> s = str(value)      #文字列
>>> value
('the answer', 42)
>>> s
"('the answer', 42)"
>>> f.write(s)
18
>>> f.close()

f.tell() ・・・ファイルの中での現在位置を示す整数を返す
f.seek(オフセット,起点) ・・・現在位置を変えたいとき
     起点:「0」ファイルの先頭(省略時)、「1」現在位置、「2」ファイルの末尾

ファイルオープンせずに読み込みエラー   ※Webはファイルの読み書きに記載.
>>> f.close()
>>> f.read()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file.

ファイルオブジェクトを扱うときはキーワードwithを使用。
一連の捜査から抜けるときファイルが正しく閉じられ、途中で例外が発生しても処理される。
同党の動作のtry-finallyブロックよりずっと短い。

ファイルオープン・読み込み   ※Webはファイルの読み書きに記載.
>>> with open('workfile') as f:
...     read_data = f.read()
...
>>> f.closed
True

ファイルオブジェクトにはisatty(),truncate()といったメソッドもあるが、ほとんど使われない

構造のあるデータをjsonに保存する  ★別途まとめる★

文字列はファイルに自由に読み書きできるが、数値は少し努力が必要。
read()メソッドは文字列しか返さないため、int()などの関数を介する必要がある。
複雑なデータになると、手動で行うのはややこしい。

PythonではJSONを簡単に扱えるようになっている

>>> import json
>>> json.dumps([1, 'simple', 'list'])
'[1, "simple", "list"]'
>>> import json
>>> x = {'name':'yamada','data':[2,3,4]}
>>> print(json.dumps(x))
{"name": "yamada", "data": [2, 3, 4]}

dump ・・・単純にオブジェクトを text file にシリアライズ
load ・・・デシリアライズ

(参照)pickleモジュール 
JSONとは対照的に、任意の複雑なPythonオブジェクトのシリアライズが可能なプロトコル。
ただし、Python固有の物であり他の言語で書かれたアプリケーションとの通信には使えない。
また、デフォルトではセキュアでない。

8章 エラーと例外 (4問,10.00%)

関数での例外発生時のエラーメッセージの表示内容が重要

構文エラー(構文解釈エラー:parsing error)

Pythonで決められたルールに従っていないため発生。
構文解釈(パース)のエラー
表示:SyntaxError

例外 (exception)

分野式が構文的に正しくても、実行するとエラーが起こる。
表示:ZeroDivisionError、NameError、TypeErrorなど
組み込み例外に組み込み例外の一覧がある

♯## 例外の処理
try文の動作
1.try節(try clause) (キーワード tryとexceptの間の文)が実行される。
2.何も例外が発生しなければ、except 節 をスキップしてtry文の実行を終了する。
3.try節の実行中に例外が発生すると、その節の残りはスキップされる。例外の型がexceptキーワードの後に指定されている例外に一致する場合、except節が実行された後、try文のあとのプログラムが継続される。
4.例外の型がexcept節にある名前と一致しない場合、創出された例外はさらに外側にあるtry文に渡されます(try文が入れ子になっている場合)。ハンドラ(handler、処理部) が見つからない場合、処理されない例外(unhandled exception)となり、上記に示したようなメッセージを出して実行を停止します。

一つのtry文に複数のexcept節を設けて、さまざまな例外に対するハンドラを指定

... except (RuntimeError, TypeError, NameError):

except 節では、例外名の後に変数を指定可能
変数は例外インスタンスに結び付けられており、instance.argsに例外インスタンス生成時の引数が入っている
例外インスタンスには__str__()が定義されており、.argsを参照しなくても引数を直接印字が可能

>>> try:
...     raise Exception('spam', 'eggs')
... except Exception as inst:
...     print(type(inst))
...     print(inst.args)
...     print(inst.args)
...     x, y = inst.args
...     print('x =', x)
...     print('y =', y)
...
<class 'Exception'>
('spam', 'eggs')
('spam', 'eggs')
x = spam
y = eggs

例外ハンドラは、try節から(たとえ間接的にでも)呼び出された関数の内部で発生した例外も処理する。(try節の直接内側で発生した例外だけでない )

else 節 (else clause)  ・・・ else 節は try 節で全く例外が送出されなかったときに実行される
  try … except 文には、オプションで else 節 (else clause) を設けることが可能
  else 節を設ける場合、全ての except 節よりも後ろに置かなければならない

for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print('cannot open', arg)
    else:
        print(arg, 'has', len(f.readlines()), 'lines')
        f.close()

例外の送出

raise 文を使って、特定の例外を発生が可能

ユーザー定義例外

新しい例外クラスを作成することで、プログラムに独自の例外を含めることが出来る。
普通のクラスができることなら何でも定義可能だが、通常は例外が発生したときにハンドラがエラーに関する情報を取り出せるようにする程度にとどめる。

class Error(Exception):
    pass

class InputError(Error):
    def __init__(self, expression, message):  # オーバーライドしている
        self.expression = expression
        self.message = message

クリーンアップ動作の定義

finally節(finally clause)は、例外が発生したかどうかに関わらず、 try文を抜ける前に常に実行される

オブジェクトに定義してあるクリーンアップ動作

下記の問題はファイルを開きっぱなしになっていること

for line in open("myfile.txt"):
    print(line, end="")

with文はファイルのようなオブジェクトが常に、即座に正しくクリーンアップされることを保証する

with open("myfile.txt") as f:
    for line in f:
        print(line, end="")

9章 クラス (2問,5.00%)

9.1. 名前とオブジェクトについて一言

オブジェクトには個体性があり、同一のオブジェクトに(複数のスコープから)複数の名前を割り当て可能。(他の言語では別名付け(エイリアシング)と呼ぶ)

9.2. Pythonのスコープと名前空間

名前空間(namespace)とは、名前からオブジェクトへの対応付け(mapping)。
スコープ(scope)とは、ある名前空間から直接アクセスできる、プログラムテキスト上の範囲。

9.3. はじめてのクラス

9.3.1. クラス定義の構文

(最も簡単な形)
class ClassName:
<文1>
.
.
.
<文N>

9.3.2. クラスオブジェクト

クラス・オブジェクトは属性参照とインスタンス化の2種類の操作をサポート。

属性参照
インスタンス化

>>> class Complex:
...     def __init__(self, realpart, imagpart):
...         self.r = realpart
...         self.i = imagpart
...
>>> x = Complex(3.0, -4.5)
>>> x.r, x.i
(3.0, -4.5)

9.3.3. インスタンスオブジェクト

インスタンス・オブジェクトは属性参照のみの操作をサポート。
属性名としてはデータ属性とメソッドの2種類が有効

データ属性(data attribute)は、Smalltalkの「インスタンス変数」やC++の「データメンバ」に相当
メソッド(method)は、 オブジェクトに「属している」関数のこと。

9.3.4. メソッドオブジェクト

9.3.5. クラス変数とインスタンス変数

・インスタンス変数はそれぞれのインスタンスについて固有のデータのためのもの
・クラス変数はそのクラスのすべてのインスタンスによって共有される属性やメソッドのためのもの

9.4. その他いろいろ

・データ属性は同じ名前のメソッド属性を上書きしてしまう
→ 衝突の可能性を最小限にするような規約を使うこと
 メソッド名を大文字で始める、データ属性名の先頭に短い一意な文字列 (あるいはただの下線) をつける、またメソッドには動詞、データ属性には名詞を用いる、など
・メソッドの最初の引数をselfと呼ぶが、この名前付けは単なる慣習でしかない
※self という名前は、 Python では何ら特殊な意味を持たない。
→ ただ、この慣行に従わないと、コードはやや読みにくいものとなる。
  クラスブラウザ(class browser)プログラムがこの慣行をあてにしているかもしれない。

9.5. 継承 (inheritance)

class DerivedClassName(BaseClassName):
<文1>
.
.
.
<文N>
※BaseClassName ・・・基底クラス (base class)
※DerivedClassName ・・・派生クラス (derived class)

9.5.1. 多重継承 (multiple inheritance)

class DerivedClassName(Base1,Base2,Base3):

DerivedClassNameにある属性が存在しない場合、まずBase1から検索され、そして再帰的に)Base1の基底クラスから検索され、それでも見つからなかった場合はBase2から検索される

ただ、実際には、これよりもう少しだけ複雑
協調的な super() の呼び出しのためにメソッドの解決順序は動的に変更される。
他の多重継承のある言語で call-next-method として知られており、単一継承しかない言語の super 呼び出しよりも強力。

9.6. プライベート変数

Python には「プライベート」インスタンス変数は存在しない。
ただ、慣習的に アンダースコアで始まる名前 (例えば _spam) はプライベートとして扱っている。

9.7. 残り物あれこれ

・Pascal の 「レコード (record)」 や、C 言語の 「構造体 (struct)」 のような、名前つきのデータ要素を一まとめにするデータ型は、殻のクラス定義うぃ使用して実装

9.8. 例外もまたクラスである ※webは8.3章内

9.9. 反復子 (イテレータ:iterator) ※webは9.8章

for文を使うとほとんどのコンテナオブジェクトにわたってループを行うことができる。

>>> for element in [1, 2, 3]:
...     print(element)
...
1
2
3
>>> for element in (1, 2, 3):
...     print(element)
...
1
2
3
>>> for key in {'one':1, 'two':2}:
...     print(key)
...
one
two
>>> for char in "123":
...     print(char)
...
1
2
3
>>> for line in open("workfile"):
...     print(line, end='')
...
0123456789abcdef2)>>>

裏では for 文はコンテナオブジェクトに対して iter() 関数を呼んでいる

・関数は、コンテナの中の要素に1つずつアクセスする next() メソッドが定義されているイテレータオブジェクトを返す。
・これ以上要素が無い場合は、next()メソッドは StopIteration例外を送出し、その通知を受けforループは終了する

組み込みの next() 関数を使って next() メソッドを直接呼ぶことも可能

>>> s = 'abc'
>>> it = iter(s)
>>> it
<str_iterator object at 0x7fc6cf183eb8>
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):  
  File "<stdin>", line 1, in <module>
StopIteration                  # StopIteration例外を送出

イテレータプロトコルの裏にある仕組みを観察していれば、自作のクラスにイテレータとしての振舞いを追加するのは簡単

next() メソッドを持つオブジェクトを返す iter() メソッドを定義する。クラスが next() メソッドを定義している場合、 iter() メソッドは単に self を返すことも可能。

>>> class Reverse:
...     """Iterator for looping over a sequence backwards."""
...     def __init__(self, data):
...         self.data = data
...         self.index = len(data)
...     def __iter__(self):
...         return self
...     def __next__(self):
...         if self.index == 0:
...             raise StopIteration
...         self.index = self.index - 1
...         return self.data[self.index]
...
>>> rev = Reverse('123')
>>> iter(rev)
<__main__.Reverse object at 0x7fc6cf18ec88>
>>> for char in rev:
...     print(char)
...
3
2
1

9.10. ジェネレータ (generator)

・ジェネレータ(generator)は、イテレータを作成するための簡潔で強力なツール
・何らかのデータを返すときにはyield文を使用
・ジェネレータに対してnext()が呼び出されるたびに、ジェネレータは以前に中断した処理を再開(状態を記録している)
※「直接アクセス可能」とは、修飾なしに(例えばspam.eggではなく単にeggのように)名前を参照可能なこと

>>> def reverse(data):
...     for index in range(len(data)-1, -1, -1):
...         yield data[index]
...
>>> for char in reverse('golf'):
...     print(char)
...
f
l
o
g

9.11. ジェネレータ式

単純なジェネレータなら、式を使って簡潔にコードする方法がある。
リスト内包に似た構文の式だが、角括弧ではなく丸括弧を使う。

>>> sum(i*i for i in range(10))
285

10章 標準ライブラリめぐり (4問,10.00%)

###10.1. OSインタフェース
osモジュール ・・・オペレーティングシステム関連

>>> import os
>>> os.getcwd()
'/root/sample/test'
>>> os.chdir('/root')
>>> os.system('mkdir today')
0

from os import * ではなく、 import os 形式を使うようにすること
※os.open()がビルトインの動作が全く異なるopen()を隠さないようにするため。

>>> import os
>>> dir(os)
>>> help(os)

shutil モジュール ・・・ファイルやディレクトリの日常的な管理作業のために、より簡単に使える高水準のインタフェース

>>> import shutil
>>> shutil.copyfile('data.db', 'archive.db')
'archive.db'
>>> shutil.move('/build/executables', 'installdir')
'installdir'

10.2. ファイルのワイルドカード

globモジュール ・・・引数に指定されたパターンにマッチするファイルパス名を取得する

>>> import glob
>>> glob.glob('*.py')
>>> glob.glob('*')   #ディレクトリ内の全てのファイル名を出力

10.3. コマンドライン引数

>>> import sys
>>> print(sys.argv)
['demo.py', 'one', 'two', 'three']

10.4. エラー出力のリダイレクトとプログラムの終了

sysモジュールには、 stdin, stdout, stderr を表す属性も存在

10.5. 文字列パターンマッチング

reモジュールでは、より高度な文字列処理のための正規表現を提供

10.6. 数学

mathモジュールは、浮動小数点演算のための C 言語ライブラリ関数にアクセスする手段を提供

>>> import math
>>> math.cos(math.pi / 4)
0.7071067811865476
>>> math.log(1024, 2)  # log(x[, base]):x の (e を底とする)自然対数
10.0
>>> math.sqrt(2)    # 平方根(ルート)を取得
1.4142135623730951

randomモジュールは、乱数に基づいた要素選択のためのツールを提供

>>> import random
>>> random.choice(['apple','pear','banana'])
'pear'
>>> random.sample(range(100), 10)
[6, 49, 57, 72, 31, 25, 35, 90, 30, 76]
>>> random.random()
0.7892340475238878
>>> random.randrange(6)
5

statisticsモジュールは数値データの基礎的な統計的特性(平均、中央値、分散等)を計算

SciPyプロジェクト は数値処理のための多くのモジュールを提供

10.7. インターネットへのアクセス

最も単純な2つのモジュールは、 URL からデータを取得するための urllib.request と、メールを送るための smtplib

10.8. 日付と時刻

datetimeモジュールは、日付や時刻を操作するためのクラスを、単純な方法と複雑な方法の両方で提供

>>> from datetime import date
>>> now = date.today()
>>> now
datetime.date(2020, 1, 3)
>>> now.strftime("%m-%d-%y. %d %b %Y is a %A on the %d day of %B.")
'01-03-20. 03 Jan 2020 is a Friday on the 03 day of January.'
>>> birthday = date(1964, 7, 31)
>>> age = now - birthday
>>> age.days
20244

10.9. データ圧縮

モジュール:zlib, gzip, bz2, lzma, zipfile, tarfile

>>> import zlib
>>> s = b'witch which has which witches wrist watch'
>>> len(s)
41
>>> t = zlib.compress(s)
>>> len(t)
37
>>> zlib.decompress(t)
b'witch which has which witches wrist watch'
>>> zlib.crc32(s)
226805979

10.10. パフォーマンスの計測

timeit モジュール

>>> from timeit import Timer
>>> Timer('t=a; a=b; b=t', 'a=1; b=2').timeit()
0.025199586991220713
>>> Timer('a,b = b,a', 'a=1; b=2').timeit()
0.022948098019696772

10.11. 品質管理

doctest モジュールでは、モジュールを検索してプログラムの docstring に埋め込まれたテストの評価を行うためのツールを提供

10.12. 電池付属です

battery included  :プログラマがすぐに使えるようなライブラリや統合環境をあらかじめ準備されている
xmlrpc.client および xmlrpc.server モジュール
email パッケージ
json パッケージ
sqlite3 モジュール
gettext, locale, codecs パッケージ

11章 標準ライブラリめぐり─PartII (1問,2.50%)

11.1. 出力整形

・reprlib モジュール  ・・・出力の長さを制限する、変更可能だがデフォルトは要素6個
 ※長すぎる出力結果を省略したい場合に使える
repr()の別バージョン  ※省略はしない

reprlib.reprとrepr.
>>> reprlib.repr('1111122222333334444455555666667777788888')
"'111112222233...6667777788888'"               # 途中省略
>>> repr('1111122222333334444455555666667777788888')
"'1111122222333334444455555666667777788888'"         #(比較)reprの結果
集合setと組み合わせ.
>>> reprlib.repr(set('1111122222333334444455555666667777788888'))
"{'1', '2', '3', '4', '5', '6', ...}"            # 集合set利用によりユニークにした上で後ろ省略
>>> repr(set('1111122222333334444455555666667777788888'))
"{'5', '3', '8', '2', '6', '1', '4', '7'}"         #(比較)reprの結果
>>> reprlib.repr({'d', 'e', 't', 'c', 'n', 'o', 'v', 'i'})
"{'c', 'd', 'e', 'i', 'n', 'o', ...}"

・pprint モジュール
・textwrap モジュール  ・・・段落で構成された文章を、指定したスクリーン幅にぴったり収まるように調整
・locale モジュール

11.2. テンプレート

string モジュールには、柔軟で、エンドユーザが簡単に編集できる簡単な構文を備えた Template クラスが入っている

>>> from string import Template
>>> t = Template('${village}folk send $$10 to $cause.')
>>> t.substitute(village='Nottingham', cause='the ditch fund')
'Nottinghamfolk send $10 to the ditch fund.'

substitute() メソッドは、プレースホルダに相当する値が辞書やキーワード引数にない場合に KeyError を送出

11.3. バイナリデータレコードの処理

structモジュール ・・・様々な長さのバイナリレコード形式を操作する pack() や unpack() といった関数を提供

>>> import struct
>>> kind, value = struct.unpack("BxH", data)
>>> data
b'd\x00\xb0\x04'

11.4. マルチスレッド

スレッド処理 (threading) とは、順序的な依存関係にない複数のタスクを分割するテクニック
マルチスレッドアプリケーションを作る上で最も難しい問題は、データやリソースを共有するスレッド間の調整 (coordination)

11.5. ログ取り

loggingモジュールでは、数多くの機能をそなえた柔軟性のあるログ記録システムを提供

>>> import logging
>>> logging.debug('Debugging information')
>>> logging.info('Informational message')
>>> logging.warning('Warning:config file %s not found', 'server.conf')
WARNING:root:Warning:config file server.conf not found
>>> logging.error('Error occurred')
ERROR:root:Error occurred
>>> logging.critical('Critical error -- shutting down')
CRITICAL:root:Critical error -- shutting down

デフォルトでは、info() と debug() による出力は抑制され、出力は標準エラーに送信

11.6. 弱参照

Pythonは自動的にメモリを管理する (ほとんどのオブジェクトは参照カウント方式で管理し、ガベージコレクション(garbage collection)で循環参照を除去する)。オブジェクトに対する最後の参照がなくなってしばらくするとメモリは解放される。

11.7. リスト操作のためのツール

11.8. 10 進浮動小数演算

decimal モジュールでは、 10 進浮動小数の算術演算をサポートする Decimal データ型を提供

Decimal クラスは厳密な値を表現できるため、2 進浮動小数点数では 期待通りに計算できないような剰余の計算や等値テストも実現
decimalモジュール・・・必要なだけの精度で算術演算

12章 仮想環境とパッケージ (1問,2.50%)

12.1. はじめに

12.2. 仮想環境の作成

pyvenv tutorial-env
tutorial-env ディレクトリがなければ作成し、中にPythonインタプリタ、標準ライブラリ、その他関連するファイルを含むサブディレクトリを作る。

12.3. pip を使ったパッケージ管理

pip search astronomy
pip install novas
pip install requests==2.6.0
pip install --upgrade requests
pip show requests
pip list
pip freeze > requirements.txt
pip install -r requirements.txt
pip uninstall request

13章 次はなに? (0問,0.00%)

チュートリアルを学んだあとの学習や各種リンク先

14章 対話環境での入力行編集とヒストリ置換 (1問,2.50%)

14.1. タブ補完と履歴編集

・変数とモジュール名の補完はインタープリタの起動時に自動で有効になっており、[Tab]キーで補完機能が呼び出せる。
・デフォルトの設定ではユーザーディレクトリの .python_history という名前のファイルに履歴を保存

14.2. 対話的インタープリタの代替

IPython
bpython

15章 浮動小数点(float)の演算:その問題と限界 (試験範囲未記載のため対象外)

浮動小数点数は、計算機ハードウェアの中では、基数を2とする(2進法の)分数として表現されている

15.1. 表現誤差 (Representation error)

表現誤差は、いくつかの(実際にはほとんどの)10 進の小数が2進法(基数2)の分数として表現できないという事実に関係している。

>>> from decimal import Decimal
>>> from fractions import Fraction
>>> Fraction.from_float(0.1)
Fraction(3602879701896397, 36028797018963968)
>>> (0.1).as_integer_ratio()
(3602879701896397, 36028797018963968)
>>> Decimal.from_float(0.1)
Decimal('0.1000000000000000055511151231257827021181583404541015625')
>>> format(Decimal.from_float(0.1), '.17')
'0.10000000000000001'
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?