Python3エンジニア基礎試験　苦戦箇所

## 短絡演算子としてのand, or
不要な評価を省略して短絡する演算子を短絡演算子という。

A and B は次のように計算する。
・Aを評価しその評価結果の真偽を判定する
・Aの判定が偽であればBを評価せずにAの評価結果を返す。
・Aの判定が真であればBを評価してその評価結果を返す。
・andがずっと続く場合、左から評価していき最初に偽になった結果が最終結果になりそこで評価をやめる。
・すべて真の場合最後の評価結果が最終結果となる。

A or B の場合
・Aを評価しその評価結果の真偽を判定する
・Aの判定が真であればBを評価せずにAの評価結果を返す。
・Aの判定が偽であればBを評価してその評価結果を返す。
・orがずっと続く場合、左から評価していき最初に真になった結果が最終結果になりそこで評価をやめる。
・すべて偽の場合最後の評価結果が最終結果となる。

## 引数にデフォルト値を設定する
```
def 関数名(引数 = デフォルト値):
```
引数のデフォルト値は関数が定義された時点で評価され関数の実行時に再評価はされない。デフォルト値のある関数を定義してから変数に値を代入してもデフォルト値に影響は与えない。

## アンパック
リスト、タプルは * を先頭に付けると要素を位置変数に展開して関数に渡せる。
ディクショナリは ** を先頭に付けると要素をキーワード変数として指定できる。

### タプルの定義
```
sample_tuple = ("spam", "ham", "eggs") #普通の書き方

sample_tuple = "spam", "ham", "eggs" # ()は省略できる。カンマさえあればいい

sample_tuple = "spam", # 要素が１つのタプルはこう書く

sample_tuple = tuple(["spam", "ham", "eggs"]) # tuple()を用いて各場合は引数がリスト型などである必要がある。
```

## ディクショナリの定義
リストはインデックスを使って値を参照・更新するのに対し、ディクショナリではキーを用いて行う。キーは文字列や数値などイミュータブルである必要がある。

## ディクショナリに特定のキーが含まれているか調べる
「値 in ディクショナリ」のようにディクショナリに対してin演算子を使うことでキーの存在を確認できる。ディクショナリのkeys()メソッドの返り値に対してin演算子を使うこともできる。list()の引数にディクショナリを与えるとキーを要素とするリストが生成される。

##　内包表記
{キーの式: 値の式 for 変数 in 反復可能体}
```
# 例
d = {x: x**3 for x in (1, 3, 6)}
```

## 相対インポート
「.」を使ったインポートは同じ階層にあるサブモジュールを参照する。「..」を使ったインポートは一つ上の階層にあるサブモジュールを参照する。
相対インポートはサブモジュールに対してのみ実行できる。

## ファイルの入出力
### open()
ファイルの操作に使用。mode引数を追加することで開き方を変更できる。
```
open("ファイル名", mode = "モード")
```
| 1 | 2 |
|:-:|:-:|
| "r" | 読み込み専用 |
| "r+" | 読み書き両用 |
| "w" | 新規書き込み |
| "a" | 追加書き込み |
| "b" | バイナリモード |

バイナリモードは単独で指定ができない。

### read()
ファイルの内容を読み込むにはread()メソッドを用いる。関数ではない。
設問はfpというファイルオブジェクトがあるのでfp.read()とすることでファイルの内容を取得できる。

### close()
open()で開けたファイルは処理後に閉じる必要がある。そんな時にclose()メソッドを使う。

### with
with文は開けたファイルを自動で閉じてくれる。例外が発生した時も自動で閉じる。
```
with open("ファイル名") as 変数:
    #何かの処理などをここに書く
```
なおプログラムが終了するときにすべてのファイルオブジェクトは閉じられる。

### ファイルを一行ずつ処理する
ファイルオブジェクトはミュータブルである。そのためfor文で回せば要素を１つずつ取り出せる。
```
for s in fp:     #推奨、一行ずつ処理する。

for s in fp.readlines():     #正しいが非推奨

for s in list(fp):     #正しいが非推奨

for s in fp.read():     #一行ずつではなく一文字ずつ処理する
```

### write()
ファイルにデータを書き込むときはwrite()メソッドを使う。
```
fp.write("...")
```
### json形式で書き込む
pythonで作成されたオブジェクトをjson形式で書き込むにはjson.dump()メソッドを用いる。
```
json.dump(data, fp)

# キーワード引数を使っても同じことができる。
json.dump(fp = fp, obj = オブジェクト)

# json.dumps()でも似たようなことはできる。
fp.write(json.dumps(data))
```
json.dumpsは文字数を返すのでキーワード引数で渡すことはできない。dumpsのsはstringのsと覚えるといいかも。

### json形式のファイルを読み込む
json形式のデータを読み込んでpythonのオブジェクトとして取得したいときはjson.load()メソッドを使う。
```
json.load(fp)

# json.loads()でも似たようなことはできる。
json.loads(fp.read())
```
json.loads()の第一引数には文字列が必要なのでjson.loads(fp)などとするとTypeErrorとなる。
## いろいろなエラー
### SyntaxError
構文エラー。

### ValueError
意図していないデータ型が与えられた時に発生する。int型が欲しいのにstr型のデータが与えられたりしたらこれが起こる。

### KeyError
ディクショナリに存在しないキーを参照しようとしたときに出るエラー。

### NameError
定義されていない変数や関数を使おうとしたときに出るエラー。

## 例外検知
例外が起きたことを検知して例外発生時の動作を実装するときにtry-except文を使う。try文の中には通常の処理を書いてexcept文の中にtry節で発生しうる例外に対する処理を書く。try節があるならexcept文が必要ないときでもexcept文は書き、節の中身はpassとする。

## クリーンアップ動作
finally節というものを追加することができ、ここで例外が発生しても最後に絶対する処理を書ける。

# クラスとインスタンス
## クラス
データと機能をひとまとめにする仕組み。新しいオブジェクトの雛型となる。似た機能を持つオブジェクトをたくさん作るのに便利。例えばRPGにおける敵キャラのステータスとか。
pythonにおけるクラスはclassから始まるクラス定義文で記述する。クラス名はSampleClassのように単語の一文字目を大文字にすることが慣例となっている。クラスを構成する要素にクラス変数、インスタンス変数、メソッドがある。
```
class クラス名:
    def __init__(self, 引数2, ...):
        self.インスタンス名 = 値
        #このように続けていく
    def メソッド名(self, 引数2, ...):
        #ここに処理を書く
        #続く
```
## クラス変数
クラスで保持する変数でそのクラスのすべてのインスタンスで保持される。
クラス変数はクラスの直下に定義する。通常の変数と同じように「変数名 = 値」のように記述する。

## インスタンス変数
インスタンスごとに固有の変数。インスタンスを初期化するための特殊メソッドである__init__()メソッドの中で定義する。__init__()メソッドにはselfというメソッドを与える。インスタンス変数は「self.変数名 = 値」の形で書く。

## メソッド
クラスに定義された関数。定義の仕方は関数と同様だが第一引数はself。メソッド内でクラス変数(あるいはほかのメソッドなど)を参照したいときはself.をつける必要がある。

## クラスの継承
Pythonでは定義済みのクラスをもとに別のクラスを作成できる。これをクラスの継承と呼ぶ。このとき継承元になるクラスを基底クラス、継承先になるクラスを派生クラスという。あるクラスを継承すると派生クラスは基底クラスからクラス変数、インスタンス変数、メソッドをそのまま引き継ぐ。
```
# インスタンス化
class Duck:
    def __init__(self, birdsong):
        self.birdsong = birdsong
    def sing(self):
        return self.birdsong
duck = Duck("quack") #ここでインスタンス化がされている。duck = Duck()のようにすることでインスタンス化される。"quack"は第二引数（第一引数はself）。

#クラスの継承
#基底クラスの作成
class Greeting:
    lang = "en"

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

    def get_hello(self):
        return f"Hello, {self.name}"

#派生クラスの作成
class GreetingJa(Greeting):
    lang = "ja" #基底クラスのクラス変数langを上書き

    def get_hello(self):
        return f"こんにちは {self.name} さん"
        
greeting = GreetingJa("太郎")
```

# いろいろな標準ライブラリ
## os
ファイルやディレクトリを操作する関数が定義されている

## glob
glob.glob(パターン)でファイル名がパターンにマッチするファイル一覧を取得できる。
## argparse
argparseモジュールのArgumentParser()を使ってもコマンドライン引数を取得できる。
```
import argparse
parser = argparse.ArgumentParser() #パーサのオブジェクトを生成
parser.add_argument("--head")
parser.add_argument("body", nargs = "+") #parserに引数の情報を追加
args = parser.parse_args() #parser.parse_args()で引数の情報を取得できる。
print(args)

### 実行結果
Namespace(head = "1", body = ["2", "3"])
```
## random
乱数を生成する。
random.choice()は複数の候補から一つをランダムに選ぶ関数。過去の出力に関係なく選ぶので結果が重複することもある。
random.random()関数は0≤x<1のランダムな小数をfloat型で返す。この範囲を数倍したり足したり引いたりして範囲をうまいこと調整する。

## URLを開けたい
urllib.requestのモジュールのurlopen()関数を使うと引数で指定したURLのWebサイトを読める。バイナリで取得するので後でdecode()で変換する必要がある。

## 単体テストをする
単体テストをしたいときはunittestモジュールを使う。unittestによる単体テストではテスト対象のモジュールとは別にテスト用データを用意する必要がある。
ファイルを作成した後コマンドラインから「python -m unittest」のように実行するとテストできる。
テストの実行結果が想定通りになっているか確認するにはself.assertEqualを用いる。assertEqualは継承元のunittest.TestCaseで定義されている。結果が違う場合は確認できる。
self.assertEqualの代わりにassertも使えるが結果がどう違うかを確認できない。
## pprint()
一行が80文字を超えると勝手に改行する。print()はしない。
## fill()
textwrapモジュールのfill()関数を使うとwidthで指定した幅に収まるように整形する。

## コマンドライン引数
コマンドライン引数はプログラムの実行時に指定できる特殊な引数。コマンドライン引数はsysモジュールのargv属性を使ってリストで取得できる。
```
python プログラム名.py 引数1, 引数2, ...
```

通りました。注意力確認試験でした。あんまり意味を感じない試験だった。