Python3エンジニア認定基礎試験（5章～6章）

前回の記事の続きです。

# 5章 データ構造
**出題数 7/ 40問(17.5%)**

### 5.1 リストのメソッド

* `append()`：要素を追加

* `extend()`：リストを追加

* `insert()`：指定位置に要素を挿入
  
* `remove()`：特定の要素を削除（同じ値がある場合は一番左を削除）

* `pop()`：特定の要素を取り出す（取り出した値を返す）

* `index()`：指定した要素のインデックスを指定範囲で確認

* `count()`：指定した要素の数を確認

* `sort()`：昇順に並べ替え（並び変えてもidは変わらない）

* `reverse()`：現在の順と逆の順で並び替え（`sort(reverse=True)`も同様）

* `clear()`：全ての要素を削除


```Python
>>> aaa_list = [2, 3, 3, 3, 4]
>>> aaa_list.append(5)
>>> aaa_list
[2, 3, 3, 3, 4, 5]

>>> aaa_list.extend([10, 11])
>>> aaa_list
[2, 3, 3, 3, 4, 5, 10, 11]

>>> aaa_list.insert(2, 99)
>>> aaa_list
[2, 3, 99, 3, 3, 4, 5, 10, 11]

>>> aaa_list.remove(3)
>>> aaa_list
[2, 99, 3, 3, 4, 5, 10, 11]

>>> aaa_list.pop(6)
10
>>> aaa_list
[2, 99, 3, 3, 4, 5, 11]

>>> aaa_list.index(3)
2
>>> aaa_list.index(3, 3, 6)
3
>>> aaa_list.index(3, 3)
3

>>> aaa_list.count(3)
2

>>> aaa_list.sort()
>>> aaa_list
[2, 3, 3, 4, 5, 11, 99]

>>> aaa_list.sort(reverse = True)
>>> aaa_list
[99, 11, 5, 4, 3, 3, 2]

>>> aaa_list.reverse()
>>> aaa_list
[2, 3, 3, 4, 5, 11, 99]

>>> aaa_list.clear()
>>> aaa_list
[]
```

* `copy()`：リストをコピー
  * `copy()`を使わないで同じ値を変数に定義すると、オリジナル側の要素を変更した場合にコピー側も同じく変更される（オリジナル側とコピー側が見ているデータが同じ）
  * **浅いコピー**は対象のオブジェクトのみ、**深いコピー**は対象のオブジェクトの参照先のミュータブルオブジェクトもコピー
※浅いコピーの場合、コピー側の参照先の要素を変更したらオリジナル側も同じ値に変更される


```Python
>>> bbb_list = [1, 2, 3]
>>> ccc_list = bbb_list
>>> ccc_list
[1, 2, 3]
>>> bbb_list[0] = 10
>>> ccc_list
[10, 2, 3]

>>> ddd_list = [1, 2, 3]
>>> eee_list = ddd_list.copy()
>>> eee_list
[1, 2, 3]
>>> ddd_list[0] = 10
>>> eee_list
[1, 2, 3]

>>> fff_list = [[1, 2], 3, 4]
>>> ggg_list = fff_list.copy()
>>> ggg_list
[[1, 2], 3, 4]
>>> ggg_list[0][1] = 5
>>> ggg_list
[[1, 5], 3, 4]
>>> fff_list
[[1, 5], 3, 4]
```

※リストが改変されるメソッドは返り値がないので、メソッドチェーンはできない（append、sortなど）


### 5.2 スタック・キュー
 * スタック：後入れ先出し
   * `.append`と`.pop`を使用

```Python
>>> list_a = []
>>> list_a.append(1)
>>> list_a.append(2)
>>> list_a.append(3)
>>> list_a
[1, 2, 3]
>>> list_a.pop()
3
>>> list_a
[1, 2]
```

 * キュー：先入れ先出し
   * `.append`と`.popleft`を使用
   * リストを`deque`に変換して使用
   * 標準ライブラリ`collections`モジュールの`deque`型を使用

```Python
>>> from collections import deque
>>> queue = deque(["a", "b"])
>>> queue.append("c")
>>> queue
deque(['a', 'b', 'c'])
>>> queue.popleft()
'a'
>>> queue
deque(['b', 'c'])
```




### 5.3 リスト内包表記
 * 記述形式：`[処理 for 変数 in 要素の集まり]`
   * 関数、メソッド、関数内関数などを使用した処理も可能
   * `for`は複数使用可能
   * `if`も使用可能


```Python
>>> squares = [x**2 for x in range(5)]
>>> squares
[0, 1, 4, 9, 16]

>>> [(x, y) for x in [1, 2, 3] for y in [2, 4, 3] if x != y]
[(1, 2), (1, 4), (1, 3), (2, 4), (2, 3), (3, 2), (3, 4)]
```


### 5.4 del

 * `del リスト[インデックス]`
   * 指定したインデックスを削除
   * popとの違いは、データを返さないこと

 * `del リスト[:]`
   * リスト内のデータを削除　
   * clearと同じ挙動

 * `del リスト`：リスト自体を削除


```Python
>>> list_a = [1, 2, 3]
>>> del list_a[0]
>>> list_a
[2, 3]

>>> del list_a[:]
>>> list_a
[]

>>> del list_a
>>> list_a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'list_a' is not defined. Did you mean: 'list'?
```


### 5.5 タプル

 * 記述形式
   * `()`を用いて宣言（`()`なしでもok）

 * リストとの違いは変更不能なこと
   * 意図しない変更を防げる

 * タプルパッキングとシーケンスアンパッキング
   * タプルパッキング：複数の値をタプルにまとめる
   * シーケンスアンパッキング：シーケンス（タプル、リスト、文字列など）を複数の値に展開

```Python
>>> tuple_a = "a", 3, [1, 2]
>>> tuple_b = (1, "b")
>>> type(tuple_a)
<class 'tuple'>
>>> type(tuple_b)
<class 'tuple'>

>>> x, y, z = tuple_a
>>> x
'a'
>>> y
3
>>> z
[1, 2]
```

 * namedtuple
   * 属性やインデックスで要素にアクセス

```Python
>>> from collections import namedtuple
>>> Car = namedtuple('Car', ('id', 'color'))
>>> my_car = Car(1, 'red')
>>> my_car[0]
1
>>> my_car.color
'red'
```



### 5.6 集合

* 記述形式
  * `{}`または`set()`関数を使用（空の集合は`set()`関数を使用）

* 重複しない要素の集まり

* 順不同

* 存在判定
  * `in`を使用

* 集合同士の計算
  * 和集合`|`、差集合`-`、積集合`&`、対象差集合`^`を使用


```Python
>>> set_a = {'a', 'b', 'i', 'e', 'p', 'e', 'b'}
>>> set_a
{'a', 'e', 'p', 'i', 'b'}
>>> set_b = set("abfgduwad")
>>> set_b
{'w', 'g', 'f', 'a', 'u', 'd', 'b'}
>>> set_c = set()
>>> set_c
set()

>>> 'a' in set_a
True
>>> 'y' in set_b
False

>>> set_a | set_b
{'w', 'g', 'f', 'e', 'p', 'i', 'a', 'u', 'd', 'b'}
>>> set_a - set_b
{'p', 'e', 'i'}
>>> set_a & set_b
{'a', 'b'}
>>> set_a ^ set_b
{'g', 'f', 'p', 'i', 'u', 'd', 'w', 'e'}
```


* set内包表記
  * 記述形式：`{処理 for 変数 in 要素の集まり}`（括弧の中はリスト内包表記と同様）

```Python
>>> squares = {x**2 for x in range(5)}
>>> squares
{0, 1, 4, 9, 16}
```





### 5.7 辞書

*  記述形式：`{key1: value1, key2: value2}`
   * 入力：キー、出力：バリュー
   * キーは変更不能な型
   * キーがタプルの場合はそのタプル内に変更可能なオブジェクトは含まない

*  dict()でも作成可

```Python
>>> dic1 = {1: 'abc', 2: 'def', 3:'ghi'}
>>> dic1[2]
'def'
>>> dic2 = {[1,2]: 'jjj'}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> dic3 = {(1, 2): 'jjj'}
>>> dic4 = {(1, [2, 3]): 'kkk'}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

>>> dic5 = dict([(4, "mm"), ("x", "yy")])
>>> dic5
{4: 'mm', 'x': 'yy'}
>>> dic6 = dict(p = "nn", q = "zz")
>>> dic6
{'p': 'nn', 'q': 'zz'}
```

*  「キー = 新しい値」で辞書内容変更可

*  辞書にないキーを指定すると追加できる

* 存在判定
  * `in`を使用してキーが辞書にあるか確認

```Python
>>> dict_a = {1:"aaa", 2:"bbb"}
>>> dict_a[1] = "xxx"
>>> dict_a
{1: 'xxx', 2: 'bbb'}
>>> dict_a[3] = "ccc"
>>> dict_a
{1: 'xxx', 2: 'bbb', 3: 'ccc'}

>>> 1 in dict_a
True
>>> 0 in dict_a
False
```




* 辞書内包表記
  * 記述形式：`{key:処理 for 変数 in 要素の集まり}`（`key:`の後ろはリスト内包表記と同様）

```Python
>>> squares = {x: x**2 for x in range(5)}
>>> squares
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
```


* list()関数
  * キーをリスト化する

* sorted()関数
  * キーをソートして取得
  * ()内を`変数.values()`にすると値をソートして取得

* items()メソッド
  * キーとバリューをまとめて取り出す

```Python
>>> dict_a = {'b': 30, 'd':10, 'c':20, 'a':40}
>>> list(dict_a)
['b', 'd', 'c', 'a']

>>> sorted(dict_a)
['a', 'b', 'c', 'd']
>>> sorted(dict_a.values())
[10, 20, 30, 40]

>>> for id, num in dict_a.items():
...     print(id, num)
...
b 30
d 10
c 20
a 40
```




### 5.8 演算子 

* 比較演算子：`in`、`is`
  * `is`は同じオブジェクトかどうかを確認
  * 同じオブジェクトかどうかは`id()`で確認できる
  * 同じ値かどうかを調べるときは`==`を使用

```Python
>>> 'a' in 'abc'
True
>>> 'a' not in 'abc'
False
>>> 'd' in 'abc'
False

>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> a == b
True
>>> a is b
False
>>> id(a)
1811344092352
>>> id(b)
1811344094720

>>> x = 5
>>> y = 5
>>> x == y
True
>>> x is y
True
>>> id(x)
140731475944360
>>> id(y)
140731475944360
```

* ブール演算子：`and`、`or`、`not`
  * 優先順位は`not` > `and` > `or`

* セイウチ演算子：`:=`を使用
  * 式中での代入が可能

* 演算子の優先順位
  * 数値演算子 > 比較演算子 > `not` > `and` > `or`


```Python
>>> True or False and not False
True

>>> s1, s2, s3 = 'a', 'b', ''
>>> s4 = s1 or s2 and s3
>>> s4
'a'

>>> y = (x := 5) + 1
>>> y
6
```





### 5.9 シーケンス同士の比較 

* 辞書的な比較
  * 再帰的に比較する
  * 文字列は**ASCII値**で比較する（ビルトイン関数`ord()`の返り値で行われる）
  ※`chr()`関数でASCII値から文字列を確認できる


```Python
>>> (1, 3) < (2, 4)
True
>>> (3, 1) < (2, 4)
False

>>> 'あい' < 'あいう'
True
>>> 'あう' < 'いえ'
True
>>> 'うあ' < 'いえ'
False

>>> 'Z' < 'A'
False
>>> 'Z' < 'a'
True
>>> ord('Z')
90
>>> ord('a')
97
>>> chr(90)
'Z'
```




### 5.10 繰り返し文を使ったテクニック

* enumerate()関数
  * for文で使用することで、リストから要素とインデックスをまとめて取り出す
  **※4章でも記載済み**

* zip()関数
  * for文で使用することで、複数のリストを一組にまとめて順に要素を取り出す

* reversed()関数
  * for文で使用することで、要素を逆の順番で取り出す

* sorted()関数
  * for文で使用することで、ソート済みのリストを使用したループ処理を実行する


```Python
>>> list_a = ["a", "b", "c"]
>>> for index, name in enumerate(list_a):
...     print(index, name)
...
0 a
1 b
2 c

>>> list_en = ["apple", "banana", "strawberry"]
>>> list_jp = ["りんご","バナナ", "いちご"]
>>> for en, jp in zip(list_en, list_jp):
...     print(en, jp)
...
apple りんご
banana バナナ
strawberry いちご

>>> for i in reversed(range(0,3)):
...     print(i)
...
2
1
0

>>> n = [1, 4, 13, 7, 2]
>>> for i in sorted(n):
...     print(i)
...
1
2
4
7
13
```



# 6章 モジュール

**出題数 2/ 40問(5%)**


### 6.1 モジュール・パッケージ・ライブラリ
* モジュール：クラスや関数などをまとめたプログラムファイル（.py）
* パッケージ：複数のモジュールの集まり（「ドット付きモジュール名」でモジュール名前空間を構造化する手段）
* ライブラリ：モジュールとパッケージの集まり


### 6.2 モジュールの呼び出し
* Python標準機能や自作のモジュールを呼び出す
  * `import モジュール名`

* 階層が異なるモジュールを呼び出す  
  * `from ディレクトリ名 import モジュール名`

* 全モジュールを一気に呼び出す
  * `from ディレクトリ名 import *`


### 6.3 関数の呼び出し

* 特定の関数を呼び出す
  * `import モジュール名.関数名`
  * `from モジュール名 import 関数名`
※関数への代入も可

* _以外で始まる全ての名前を呼び出す（クラス・関数）
  * `from モジュール名 import *`
※`_`から始まるものは呼び出されない

* 指定した名前で呼び出す
  * `as`を使用



### 6.4 モジュールについて

* 再利用可能

* 変数にもアクセス可能
  * `モジュール名.変数名`

* モジュールを修正した場合
  * 再起動が必要
  * もしくは`importlib.reload()`を使用

* `__name__`の値
  * モジュールをインポートした場合はモジュール名
  * コマンドラインから実行する場合は`__main__`


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

* `if __name__ == “__main__”`の構文を追記
  * 意味：コマンドラインから実行されるファイルであれば次の処理を実行する

* `sys.argv`
  * 実行したプログラムのファイル名やコマンドライン引数を含んだリスト
  * `sys`（モジュール）をインポートし、`sys.argv[1]`と記述することで、渡されたコマンドライン引数を取り出す


### 6.6 モジュールの検索パス

* モジュールをインポートした際の動作
  * その名前の組み込みモジュールを`sys.builtin_module_names`から探す
  * 見つからなかった場合は`sys.path`のディレクトリのリストから探す
※`sys.path`のディレクトリは以下のとおり
    1. 入力スクリプトと同じ階層（/content）
    2. PYTHONPATH（環境変数）に登録されているパス
    3. モジュールのインストール先

* 検索パスにシンボリックリンクは追加されない

* `sys.path`は修正可能
  * リストの操作で改変できる

* 検索パスの先頭はスクリプトファイルを含むディレクトリ


### 6.7 モジュールのキャッシュ機能

* コンパイル済みのモジュールをキャッシュし、モジュールの読み込みを高速化
  * コンパイルされたモジュールは\_\_pycache\_\_ディレクトリに保存される
  * \_\_pycache\_\_ディレクトリ内の.pycファイルにキャッシュされている
  * .pycファイルを参照することでモジュールの読み込みを高速化する

* コマンドラインから直接モジュールが読み込まれた場合はキャッシュのチェックは行われない


### 6.8 標準モジュール

* プラットフォーム依存：winregモジュール（Windowsのみ）

* すべてのインタープリタ内：sysモジュール（修正可能）


### 6.9 dir()関数

* モジュールに定義している名前を確認
  * 変数、関数など

* ビルトインの関数名や変数名はリストアップしない
  * bultinsモジュールで定義されているもの
  * 予約語（変数名、関数名、クラス名など名前として使えないもの。False、andなど）

* 引数なしの場合は現在のローカルスコープで定義されている名前のリストを返す
  * 以下の例の場合：dir()でfunc、xを返し、func()内のdir()でyを返している

例
```Python
>>> x = 3
>>> def func():
...     y = x + 5
...     print(dir())
...
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'func', 'x']
>>> func()
['y']
```



### 6.10 パッケージの作成

* \_\_init\_\_.py
  * 作成したディレクトリに\_\_init\_\_.pyファイルを作成すると、そのフォルダはパッケージとして扱われる
  * 初期化コードの実行や__all__変数の設定が可能

* 初期化コードの実行
  * \_\_init\_\_.pyのファイル内に例えば`from package import module1`の記載があれば、パッケージをインポートした時点でmodule1も呼び出していることになる

* __all__変数の設定
  * `from パッケージ import *`で呼び出すモジュールを制御する
  * \_\_init\_\_.pyのファイル内で例えば`__all__ = ["module1"]`のように設定すれば、module1を呼び出すことができる
  * `from パッケージ import *`の形式は非推奨


### 6.11 パッケージの呼び出し・実行方法

* 呼び出し
  * `import パッケージ.モジュール`
  * `import パッケージ.サブパッケージ.モジュール`
  * `from パッケージ import 名前`　　（名前衝突がない場合に推奨される形式）
　※名前→モジュール、サブモジュールや関数、クラス、変数など
　
* 実行
  * インポート時の名前で実行



### 6.12 パッケージ内参照

* 相対インポート
  * 同じ階層：`from . import モジュール名`
  * 一つ上の階層：`from .. import モジュール名`
  * 異なるパッケージの内部：`from ..パッケージ名 import モジュール名`

* トップレベルのパッケージを超えた上位ディレクトリは参照できない



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

* __path__の拡張
  * \_\_init\_\_.pyに以下を記載
> from pkgutil import extend_path
> \_\_path\_\_ = extend_path(\_\_path\_\_, \_\_name\_\_)





　　
　　
エンジニアファーストの会社　[株式会社CRE-COエンジニアリングサービス](https://www.cre-co.jp/)