独習Python入門 -1日でプログラミングに強くなる-（技術評論社）学習メモ

#はじめに

独習Python入門　―1日でプログラミングに強くなる！
https://gihyo.jp/book/2016/978-4-7741-8329-9

- 上記の書籍（以下、本書）を学習した記録をまとめたものです。
- 基本的には一度解釈した内容を自分の言葉で置き換えて書いています。
    - 誤った記載があった場合は、私のミスです。
- なるべくオリジナリティがある部分の引用は避けていますが、本書の記載内容やコードをそのまま転記する際にはその旨明記します。



#1.はじめてのプログラミング

- プログラムとは何か
- Pythonのインストール
    - https://www.python.org/downloads/
- 四則演算を試す
- `>>>`　対話モード時のプロンプト
- データ型
    - 数値型
        - 整数
        - 浮動小数点数
        - …
    - 文字列
    - 真偽型
- 演算子
    - 算術演算子
    - 比較演算子
    - 代入演算子
- 文字コード
- 変数

#2.条件で分ける方法（分岐の基礎文法）

- 開発環境のセットアップ
    - https://atom.io/
- ディレクトリの概念
    - 絶対パス
    - 相対パス
- 条件分岐

```python:if文の書式
if <判断条件>:
  <条件に合致した場合の実行内容>
```
`:`が付く次の行での実行内容をブロックと呼ぶ。
ブロックであることはインデントして表現する。
インデントを正しく行っていないと以下のエラーが表示される。
`SyntaxError: expected an indented block`

```python:elseを伴う場合
if <判断条件>:
  <条件に合致した場合の実行内容>
else:
  <条件に合致しなかった場合の実行内容>
```

```python:elifを伴う場合
if <判断条件>:
  <条件に合致した場合の実行内容>
elif <条件に合致しなかった場合の追加の判断条件>:
  <追加の判断条件に合致した場合の実行内容>
else:
  <追加の判断条件に合致しなかった場合の実行内容>
```
- 条件の組み合わせ
    - and
    - or
    - not
- 予約語
- print関数
- input関数
    - `input('aaa')`
        - aaaを標準出力に書き出したのち、入力を文字列に変換して返す
- int関数
    - `int(bbb)`
        - bbbを数値型に変換する
- float関数
    - `float(ccc)`
        - 浮動小数点数に変換する

#3.繰り返しさせる方法（反復の基礎文法）

- 配列
- インデックス
- `[ ]`で括る


```python:配列の指定
<配列型の変数名> = [値1,値2,…]
``` 
配列に存在しないインデックスを指定した場合のエラー。
`IndexError: list index out of range`

for文は、配列と、そこから取り出した値を入れる変数とセットで使う。

```python:for文
for <変数> in <配列>:
  <実行する内容>
```

```python:if文のサンプル
hairetu = ["a","b","c"]
for hennsuu in hairetu:
  print(hennsuu)
```
```python:上記の実行結果
a
b
c
```
- Don't Repeat Yourselfの精神
- break
    - 条件に合致した場合に以降の繰り返し処理を中断
- continue
    - 条件に合致した場合、該当箇所のみ処理をスキップ

whileは条件に合致しなくなるかbreakするまで処理を繰り返す。

```python:while文
while <条件>:
  <実行する内容>
```
- #でコメントを入れる

#4.関数を使ってみよう！

##組み込み関数
 - 引数と戻り値の考え方
 - 組み込み関数
    - len関数
        - 文字列の長さや配列の要素数を返す
    - pow関数
        - 引数が2つの場合は累乗した値を、3つの場合は前者2つの掛けた値を3つ目で割った場合の余りを返す
    - max関数
    - min関数
    - range関数

引数のデータ型を混在させた場合に出るエラー例。
`TypeError: '<' not supported between instances of 'str' and 'int'`

公式リファレンス
https://docs.python.org/ja/3/library/functions.html
 
##自作の関数

```python:関数の定義の仕方
def <関数名>(<引数>):
  return <戻り値>
```

引数として与えられた文字列に`dayo!`を結合したものを返す関数「kannsuu」

```python:サンプル
def kannsuu(aaa):
  return aaa + 'dayo' + '!'

xxx = kannsuu('Kojima')
print(xxx)
```
```python:実行結果
Kojimadayo!
```
- ネストしてif文を含む関数の例
- 戻り値の定義は必須ではない
- 関数の定義の思想
    - 汎用性を意識する
    - 引数は少なめにする
    - 戻り値はシンプルにする


##ほかの関数（import）
組み込み関数以外の関数は`import`してからでないと使用できない。
コードは本書から抜粋。

```python:importを用いる例
>>> import platform
>>> x = platform.system()
>>> print(x)
Windows
```
 
#5.いろいろな型を学ぼう
##辞書型
- 数値
- 文字列
- 真偽
- 配列
- 辞書型
    - `{ }`で括る

```python:辞書型の作り方1
<変数名> = {
  '<キーワード1>': '要素1',
  '<キーワード2>': '要素2',
  '<キーワード3>': '要素3',
}
```
```python:辞書型の作り方2(dict関数)
<変数名> = dict(
  <キーワード1>='要素1',  
  <キーワード2>='要素2',  
  <キーワード3>='要素3',
)
```
辞書型もfor文による繰り返しに対応している。`for <変数> in <辞書型>`

##キーワード可変長引数

 関数の引数に辞書型を指定する場合、`**`を付与しておけば任意数の引数を渡せる。

```python:キーワード可変引数を受け付ける関数
def kannsuu(**aaa):
  return len(aaa)

xxx = kannsuu(Inu='Wann',Neko='Nyann')
print(xxx)
```
```python:実行結果
2
```
引数aaaに`**`を付与していない場合は以下のエラーが出る。
`TypeError: kannsuu() got an unexpected keyword argument 'Inu'`

##タプル
- 変更ができない配列のようなもの
- `( )`で括って`,`で区切る
- `( )`が無くてもいい

タプル型の要素を変更しようとするとエラーが出る。

```python:タプル型の要素を変更しようとした場合
>>> tuphenn = ('a','b','C')
>>> tuphenn[1] = 'B'
Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    tuphenn[1] = 'B'
TypeError: 'tuple' object does not support item assignment
```
キーワード可変長引数の時は`**`だったが、`*`を付与することでタプルを任意の数、引数として渡すことができる。

##集合

- 要素の重複が排除された配列のこと
- `set()`関数を使う

```python:set関数
>>> set([1,2,3,4,5,5,5,6,7,7,8,9])
{1, 2, 3, 4, 5, 6, 7, 8, 9}
```
- 和集合 `A | B`
- 差集合 `A - B`
- 積集合 `A & B`
- 排他集合 ` A ^ B`

##None
ナン。

#6.エラーと例外を使いこなす
- 正常系／異常系
- エラー
    - 構文エラー
        - 実行する前に文法でこけている
        - `SyntaxError:`
    - 例外
        - 構文としては問題ないけど実行しようとしてエラー
        - `IndexError:`
        - `ZeroDivisionError:`
        - `FileNotFoundError:`
            - `open(<開くファイル>,<開くモード>)`
        - …
- 例外処理
    - プログラムの実行環境に問題がある
    - 事前条件が満たされていない

```python:try~except文
try:
 <処理内容>
except <例外の種別> as <例外内容を格納する変数名>:  #asとそのあとの変数名は省略可能
  <例外処理>
finally:　#省略可
  <例外が発生してもしなくても実行したい内容>
```
- open関数などと組み合わせて使うwith構文
    - finallyでのcloseを指定しなくてもよくなる

#7.オブジェクトとクラスとは何か？

##オブジェクトとは

公式リファレンスより抜粋。
https://docs.python.org/ja/3.7/reference/datamodel.html

>Python における オブジェクト (object) とは、データを抽象的に表したものです。Python プログラムにおけるデータは全て、オブジェクトまたはオブジェクト間の関係として表されます。(ある意味では、プログラムコードもまたオブジェクトとして表されます。これはフォン・ノイマン: Von Neumann の "プログラム記憶方式コンピュータ: stored program computer" のモデルに適合します。)
すべての属性は、**同一性 (identity)、型、値をもっています。** 同一性 は生成されたあとは変更されません。これはオブジェクトのアドレスのようなものだと考えられるかもしれません。

- オブジェクトの要素
    - ID
    - 型
    - 値

```python:Hennsuオブジェクト
>>> Hennsuu = 'Hoge' #変数を定義
>>> id(Hennsuu)
54274624         #ID
>>> type(Hennsuu)
<class 'str'>　#型（文字列型）#ここでのclassは「オブジェクトとクラス」におけるクラスとは別物
>>> print(Hennsuu)
Hoge　　　　　#値
```

```python:Hairetsuオブジェクト
>>> Hairetsu = [1,2,3]　#配列を定義
>>> id(Hairetsu)
54324280                #ID
>>> type(Hairetsu)
<class 'list'>　　　　　 #型（配列型）
>>> print(Hairetsu)
[1, 2, 3]　　　　　　　　 #値
```
オブジェクトの後に`.`をつけることで「オブジェクトが保有している関数を呼び出すことができる」と本書では表現している。

```python:str.upper
>>> Hennsuu = 'hOge'
>>> Hennsuu.upper()
'HOGE'
```
このあたりは完全に理解が追い付いていないが、関数のうち、オブジェクトの後ろに`.`を付与して記載する方式のものをメソッドと呼ぶのかと捉えている。上記の例のうち、「`Hennsuu`が保有している関数」というのは違和感があるので、「オブジェクト`Hennsuu`の型である文字列型が保有する関数（メソッド）を、オブジェクトの後に`.`を付与する書き方をすることで呼び出すことができる」という解釈の仕方をした。

文字列メソッドの一つstr.upper
https://docs.python.org/ja/3/library/stdtypes.html#str.upper

##クラスとは

- オブジェクトの情報や振る舞いを定義したテンプレートがクラス
- クラスから生成されたオブジェクトがインスタンス
- オブジェクトやクラスを定義すると拡張性が高くなるのでうれしい

```python:クラスの定義
class <クラス名>:
  <クラスの変数の定義>
```

```python:クラスの定義および変数の代入例
class Seito:
  Kokugo = 0
  Suugaku = 0
  Eigo = 0

Kato = Seito()
Kato.Kokugo = 80
Kato.Suugaku = 70
Kato.Eigo = 50

Takahashi = Seito()
Takahashi.Kokugo = 90
Takahashi.Suugaku = 60
Takahashi.Eigo = 0

print(Kato.Suugaku)
print(Takahashi.Kokugo)
```
```python:実行結果
70
90
```

##クラスで関数を定義する
`class`内でインデント下げて`def`する際は、第一引数として`self`を用いる。

```python:classでdefする
class Seito:
  Kokugo = 0
  Suugaku = 0
  Eigo = 0

  def Heikinn(self):
    return (self.Kokugo + self.Suugaku + self.Eigo) / 3

Kato = Seito()
Kato.Kokugo = 80
Kato.Suugaku = 70
Kato.Eigo = 50

print(Kato.Heikinn())
```
```python:実行結果
66.66666666666667
```
##クラスの継承

```python:クラスの継承
class <クラス名>(<継承元のクラス名>):
  <クラスの定義>
```
継承元のクラスをスーパークラスという。

```python:クラスの継承例
class Seito:
  Kokugo = 0
  Suugaku = 0
  Eigo = 0

class Jidou(Seito):
  pass           #何も定義しない

Suzuki = Jidou()
Suzuki.Kokugo = 70    #クラスJidouで定義していない変数を使用できる

print(Suzuki.Kokugo)
```

```python:実行結果
70
```

継承先のクラスでクラスの定義を上書きすることが可能。

```python:関数の上書き
class Seito:
  Kokugo = 0
  Suugaku = 0
  Eigo = 0

  def Heikinn(self):
    return (self.Kokugo + self.Suugaku + self.Eigo) / 3

class Jidou(Seito):
  Sannsuu = 0

  def Heikinn(self):
    return (self.Kokugo + self.Sannsuu + self.Eigo) / 3
  
Suzuki = Jidou()
Suzuki.Kokugo = 70
Suzuki.Sannsuu = 50
Suzuki.Eigo = 60

print(Suzuki.Heikinn())
```
```python:実行結果
60.0
```

#8.自分が書いたプログラムをテストする

- テストするプログラムを作ってテストさせるとよい
    - プログラムの要件が明確になる
    - 再利用できる
    - プログラムが洗練される
    - デグレを防げる

`unittest`モジュールを使ったテストの例。
関数やクラスの名称以外は本書の内容を転記したもの。

```python:unittestのテスト
import unittest

def tashizann(a,b):
    return a + b

class tashizann_kakuninn(unittest.TestCase):        #1
  def test_tashizann(self):         #2
      self.assertEqual(10,tashizann(2,8))      #3

if __name__ == "__main__":        #4
    unittest.main()
```

```python:実行結果
.
----------------------------------------------------------------------
Ran 1 test in 0.008s

OK
```
---
ちなみに上記のファイルの名称を`unittest.py`にして動かしたら以下のエラーが出た。
`AttributeError: module 'unittest' has no attribute 'TestCase'`

理由を自分の言葉で表現できるほどは理解が追い付かなかったので、調べた際のサイトのリンクを貼っておく。（`unittest`モジュールが、最初にimportしたものでなく、ファイル名で指定されたものだと認識されて、unittest.pyの中には`TestCace`という属性は定義されていないよ、というエラーなのだろうか。）

https://www.daniweb.com/programming/software-development/threads/310177/wtf-unittest-testcase-doesn-t-exist

---

上記のコードでやっていることのメインとしては、`#3`のところの部分でtashizann関数に2と8を引数として与えた場合の戻り値と、期待する値10を比較させて、一致していれば`OK`が返ってくるというもの。

それを行う上で注意点がいくつかある。
- `#1`　unittestモジュールのTestCaseクラスを継承すること
- `#2`　テストを実行する関数には`test_`から始まる名称をつけること
- `#4`　おまじない。

おまじないについては、以下のサイトを参照し、「他のプログラムからimportされた時に実行されないようにするため」という位置づけのものだと捉えた。

[Pythonのif __name__ == "__main__" とは何ですか？への回答](https://blog.pyq.jp/entry/Python_kaiketsu_180207)

テストでエラーが発生した場合は以下のような結果に。


```python:unittestでエラーが出る場合
import unittest

def tashizann(a,b):
    return a + b

class tashizann_kakuninn(unittest.TestCase):
  def test_tashizann(self):
      self.assertEqual(20,tashizann(4,13))   #ここの値を変更

if __name__ == "__main__":
    unittest.main()
```

```python:実行結果

F
======================================================================
FAIL: test_tashizann (__main__.tashizann_kakuninn)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "<実行したプログラムのファイルパス>", line 8, in test_tashizann
    self.assertEqual(20,tashizann(4,13))
AssertionError: 20 != 17

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures=1)
```
assertEqual以外にも様々なメソッドがある。

[アサートメソッド一覧]
https://docs.python.org/ja/3/library/unittest.html#assert-methods

#9.明日から使えるWebプログラミング
- スクレイピング
- HTML
    - タグ
- CSS
    - セレクタ

スクレイピングに便利なBeautifulSoupという外部ライブラリのインストール。

```
>pip3 install beautifulsoup4
Collecting beautifulsoup4
  Downloading https://files.pythonhosted.org/packages/1d/5d/3260694a59df0ec52f8b4883f5d23b130bc237602a1411fa670eae12351e/beautifulsoup4-4.7.1-py3-none-any.whl (94kB)
    100% |████████████████████████████████| 102kB 1.1MB/s
Collecting soupsieve>=1.2 (from beautifulsoup4)
  Downloading https://files.pythonhosted.org/packages/b9/a5/7ea40d0f8676bde6e464a6435a48bc5db09b1a8f4f06d41dd997b8f3c616/soupsieve-1.9.1-py2.py3-none-any.whl
Installing collected packages: soupsieve, beautifulsoup4
Successfully installed beautifulsoup4-4.7.1 soupsieve-1.9.1
You are using pip version 9.0.1, however version 19.1.1 is available.
You should consider upgrading via the 'python -m pip install --upgrade pip' command.
```
スクレイピングの実行例。（変数名とアクセス先以外は本書の内容を借用。)

```python:yahooニュースのページからh1タグに設定されている文字をとってくる
import urllib.request
from bs4 import BeautifulSoup
Syutokusaki = urllib.request.urlopen('https://news.yahoo.co.jp')
Kaiseki = BeautifulSoup(Syutokusaki,"html.parser")
print(Kaiseki.find('h1').text)
```

```python:実行結果
Yahoo!ニュース
```

#10.Webアプリケーションことはじめ

- HTML
- CSS
- JavaScript
- HTTP
    - プロトコル
- Webサーバ
    - 動的
    - 静的
- データベース
- SQL
- セキュリティ
- プログラム

pythonで`http.server`というモジュールを利用してWebサーバを動かすことができる。
以下のコードは本書から引用。

```python:pythonでwebサーバを動かす
import http.server
http.server.test(HandlerClass=http.server.CGIHTTPRequestHandler)
```
上記のプログラムを実行すると、そのプログラムの格納パスをドキュメントルートとしてwebサーバが実行される。index.htmlなどを作成して格納しておけば、ブラウザで`http://locallhost:8000`でアクセスすることでその内容が参照できる。

```python:実行結果
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
127.0.0.1 - - [21/May/2019 00:11:17] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [21/May/2019 00:11:42] "GET / HTTP/1.1" 200 -
```
アクセスがあった場合、その内容が上記のように記録される。

- `cgi.FieldStorage()`関数を使用したユーザの入力を受け付けるページの作成

#11.今後の学習に向けて

- 振り返り
    - #1.
        - 変数
    - #2,#3.
        - Don't Repeat Yoursekf
        - 入れ子を避ける
        - 配列に慣れる
    - #4,#5
        - 関数
        - 辞書型
    - #6.
        - エラーを制すものはプログラムを制す
    - #7.
        - オブジェクト
            - データ
            - 処理
        - 要件を主語と述語でシンプルに表現する
    - #8.
        - 自分の書いたプログラムをテストするプログラムを書く
    - #9､#10
        - スクレイピング
        - Webアプリケーション
- 次に何を学ぶか
    - 動くプログラムを読み書きすることが最短ルート
    - データベース
    - HTMLとCSS
    - 学習曲線
        - 潜伏期間がある
    - プログラミングによって何をしたいか

#終わりに
まさに初心者向けの入門書という感じでとっつきやすく書かれているので、初めから順番に手を動かしながら読んでいけば大まかにpythonの基礎が理解できると思います。似たような初心者向けの書籍を並行して読んでいると、なんとなく勘所が分かってきて面白いです。この記事の一番の想定読者は「一度本書を読んだ自分」なので、この記事だけを読んでも内容は入ってこないかと思いますが、どこかしらが学習のとっかかりになれば幸いです。