Upgrade to Pro — share decks privately, control downloads, hide ads and more …

1日で基本が身につく! Python超入門

1日で基本が身につく! Python超入門

私が技術評論社から出版したPythonの入門書をベースとしたトレーニング資料です。
出版元の承諾をえたうえで400P近いスライドにして公開します。
企業の自社研修や大学/社会人の勉強会などに利用してもらって構いませんが、再販などの営利利用はお控えください。
後半にはおまけ資料としてプログラミングのレベルマップとレベル向上法および、駆け出しエンジニア向けにインフラエンジニアの世界をまとめています。

Ebaf5fd2c63aa33c66b0894034ae87af?s=128

yuichi

May 20, 2020
Tweet

Transcript

  1. Python3 無料トレーニング資料 (技術評論社公認) 内容 • 解説資料(1-2時間) x 8章 • 演習

    x 8章 • おまけ(プログラミング上達法) オリジナルの書籍 副読本もしくは次のステップにご利⽤ください!! Amazon: たった1⽇で基本が⾝に付く! Python超⼊⾨
  2. ⽬次 はじめに Python3をWindowsとMacにインストールしよう Pythonでプログラミングを始めよう 制御構⽂を理解しよう 関数の使い⽅をマスターしよう オブジェクト指向を理解しよう クラスの使い⽅をマスターしよう モジュールを利⽤しよう ファイルの読み書きと例外処理を⾏おう

    アプリケーションを作成しよう おまけ。レベル別プログラミングスキル向上法など CHAPTER 1 CHAPTER 2 CHAPTER 3 CHAPTER 4 CHAPTER 5 CHAPTER 6 CHAPTER 7 CHAPTER 8
  3. はじめに • この資料は技術評論社より出版されている「たった1⽇で基本 が⾝に付く! Python超⼊⾨(ISBN978-4-7741-9112-6)」を著者 (伊藤裕⼀)が出版社の許諾を得てトレーニング資料として公開 しております。 • 個⼈だけでなく企業や組織も利⽤できますが、本資料⾃体や改 変したものを営利⽬的(販売、有償トレーニング)で利⽤するこ

    とは禁⽌いたします。⼤学での講義や社内トレーニングでの利 ⽤は問題ありませんが、当資料を改変して出⾃を不明にするこ とはお控えください。 • 本資料内で利⽤している図などの著作権は技術評論社及び著者 に帰属します。本資料外で利⽤することはお控えください。
  4. 皆様へのお願い • 書籍を底本として当資料のみでPython3を学べる構成としてお りますが、書籍はトレーニング講師の解説に相当する丁寧で詳 細な説明がされています。 • 書籍及び当資料の制作にもコストがかかっていますので、オリ ジナルの書籍を副読本もしくは本資料を完遂した次の学習ス テップとして購⼊頂けると出版社及び著者としては幸いです。 •

    Amazon: たった1⽇で基本が⾝に付く! Python超⼊⾨
  5. サンプルファイルのダウンロード • 以下のURLより書籍で利⽤しているサンプルファイルをダウン ロードできます。 • 書籍の内容が本スライドと100%同⼀ではないため、使わない ファイルやここにないファイルがあることにご留意ください。 • http://gihyo.jp/book/2017/978-4-7741-9112-6/support

  6. 広告(1): 技術評論社(書籍出版元) • DockerとKubernetesの書籍を2020年夏に販売 • コンテナの基礎に加えて開発技法やコンテナベースアプリケー ションのCI/CD環境の構築なども扱う 書籍表紙絵 (あとで更新) ⽬次

    • Dockerを使ってみよう • イメージの利⽤と開発を体験しよう • ネットワークとストレージ • Dockerfileでイメージ作成しよう • Composeを使ってマルチコンテナアプリを作ろう • DockerアプリでCI/CDしよう • Kubernetes⼊⾨ • Kubernetesの利⽤
  7. 広告(2): Nutanix(トレーニング資料作成) • プライベートクラウドの構築ソフトウェア開発会社 • AWS類似のクラウドをオンプレミス(⾃社内)に数時間で構築可能 • ご相談は「https://www.nutanix.com/jp」へ • インフラ⾃動化やDevOps系は著者が⽀援可能

    ネットワーク機器 (L2/L3スイッチ) サーバー サーバー サーバー サーバー クラスタ(冗⻑化と障害時の⾃動回復) 簡単な構築作業 1. サーバーをラックに設置 2. 物理スイッチにケーブル接続 3. 構築ツールで⾃動構築 構築ツール (VMアプライアンス) GUIでIP設定など (約10分) アプライアンスがサーバーを検出して インストール指⽰後は⾃動で構築(約1時間) • ブラウザ管理画⾯(⽇本語) • ハイパーバイザー • ファイルサーバー • ブロックストレージ • オブジェクトストレージ • バックアップ • マネージドKubernetes • マネージドデータベース • パブリッククラウド連携 • マイクロセグメンテーション • VDI(仮想デスクトップ基盤) • 監視、その他 ほぼフルスタックなクラウド機能 使いやすい操作画⾯(REST APIサポート)
  8. 著者について • Nutanix社のソリューションスペシャリスト(DevOps)。開発 + インフラ屋 • 得意領域 • ソフトウェア開発およびDevOps(CI/CD) •

    コンテナとオーケストレーション • モダンアプリケーション開発と⾃動化 • パブリック/プライベートクラウド • ネットワーク(L2/L3) • サーバー仮想化(VMWare, KVM) • サーバーOS(Linux) • 略歴(英語): LinkedIn(@yuichiito) • 副業で技術書や記事の執筆。企業や⼤学向け技術資料作成をしています • 仕事依頼はメールでyuichi@yuichi.comにお願いします 出版社様へ。中級者を想定したモダンなLinuxの使い⽅の本を書きたいです。 Twitter(@yuichi110)
  9. WindowsにPython3をインストールする (1/3) • WindowsにはPythonはインストールされていない • 公式サイト(https://www.python.org/)にアクセスする • 「Python3」のインストーラーをダウンロードし起動

  10. WindowsにPython3をインストールする (2/3) • インストーラーをブラウザもしくはダブルクリックで起動

  11. WindowsにPython3をインストールする (3/3) • インストーラーのガイドにしたがってインストール • 「パスを通すにチェックをつける(4)」を忘れないこと

  12. MacにPython3をインストールする • Macには標準でPythonがインストールされているが古い(2系) • 公式サイトからPython3系のインストーラーを⼊⼿しインス トールを実施。ガイドにそってインストール • Mac標準のPython2でPython3を想定した本トレーニングのプ ログラムは実⾏できない場合が多いのでご注意ください。

  13. Pythonでプログラミングを始めよう CHAPTER 1 1. プログラミングとPythonについて知る 2. Pythonで電卓代わりに計算する 3. 値を格納する「変数」を理解する 4.

    データの種類を決める「型」を理解する
  14. プログラミングとPythonについて知る • このセクションで学ぶこと • プログラムってなに? • プログラミング⾔語の存在意義 • なぜプログラミング⾔語としてPythonを選ぶか •

    コンパイル型とインタプリタ型の⾔語の違い SECTION 01
  15. プログラムはコンピューターへの指令書 • 「プログラム」は機械に「こう動け」と命令する指令書 • PCのアプリだけでなく、ブラウザのサービス(検索エンジンや ウェブメールなど)も提供会社側でプログラムが動いている • プログラムを書くこと「プログラミング」という • プログラムのことを「コード」、プログラミングのことを

    「コーディング」ともいう
  16. プログラミング⾔語で機械への命令が簡単に • 機械は電気のON/OFF(01の2進数)で状態を管理している • 最終的に01で命令を機械に伝える必要があるが、⼈間が01を扱 うことは難しい • プログラミング⾔語は「01しか使えない機械」と「⾃然で曖昧 な⾔葉を使う⼈間」の間にある「厳格な⽂法の⼈⼯⾔語」 •

    ⼈間がプログラミング⾔語で命令を書き、機械がそれを01に変 換して解釈実⾏する ⼈間の領域 (曖昧) 機械の領域 (01) プログラミング⾔語
  17. Pythonを選ぶ理由 • 「なにをやりたいか(⽬的)」に応じて使うプログラミング⾔語 は変わってくる • Pythonは「簡単である(すぐに覚えられる、同じプログラムを 他の⾔語より素早く書ける)」ことに加えて、「広範囲の開発作 業に使える」「インタプリタ型」という特徴があるのでおすす め

  18. コンパイル型とインタプリタ型の⾔語の違い • コンパイル型: プログラミング⾔語から機械語(01)に事前変換 • インタプリタ型: 実⾏時にプログラミング⾔語から機械語に変換 • Pythonはインタプリタ型の⾔語 •

    インタプリタ型はコンパイルの⼿間(時間)がないので開発が楽
  19. Pythonが苦⼿なこと • 超⾼速性が求められるシステムやデスクトップアプリケーション(⼀ 般ユーザー向けの再配布)、組み込み機器の開発が苦⼿。多くのスク リプト系⾔語も全く同じ領域が苦⼿ • ⾼速な処理(科学計算系はライブラリが⾼速なので問題なし)。⼀般 的にインタプリタ型はコンパイラ型に⽐べると実⾏時にコンパイル するので遅い。速度は⾔語より設計やアルゴリズムに起因すること が多いので、⾔語の速度はプログラミング上級者になってから気に

    すれば問題なし • Pythonがインストールされている環境でPythonアプリを利⽤するこ とは簡単だが、Pythonがインストールされていない環境(⼀般ユー ザーのPC)で動かすのは不可能ではないものの⼿間がかかる。 • 組み込み機器のような機械に近いレイアはPythonが使えないことが 多い 。基本は汎⽤OSの上でPythonを使う
  20. 汎⽤性の⾼さもPythonの魅⼒ • プログラミング⾔語には得意苦⼿がある • 様々なことが得意な⾔語を学べば何にでもその⾔語を使える • 利⽤⽬的が限られる⾔語は⽬的ごとに複数⾔語の習得が必要 • C⾔語: OSに近い領域や組み込み向けのプログラミングが得意

    • Python • 使い捨ての短い簡単なスクリプトでも使える • ⼤規模なシステムの開発でも使える • ウェブサービスの開発でも使える • 科学計算(機械学習/ビッグデータ処理など)でも使える
  21. プログラミング⾔語の分類とPython • プログラミング⾔語は以下の3種類に分類できる • ⼿続き型⾔語(オブジェクト指向型⾔語のベース) • オブジェクト指向型⾔語(現在の主流。Pythonも) • 関数型⾔語 •

    ただしPythonは⼿続き型のような書き⽅もできるし、関数型の ような書き⽅(中上級者向け)もできる ⼿続き型 ⾔語 オブジェクト 指向型⾔語 関数型 ⾔語 Python
  22. • なぜプログラムの作成にアセンブリ⾔語ではなくモダンなプロ グラミング⾔語を使うべきか説明してください • コンパイル型とインタプリタ型のプログラミング⾔語の違いを 説明してください • スクリプトやウェブサービスの開発にC⾔語ではなくPythonを 使うべき理由を説明してください •

    Pythonが苦⼿な領域を説明してください 演習
  23. Pythonで電卓代わりに計算する • このセクションで学ぶこと • Pythonの起動⽅法: Windows, Mac • Pythonのバージョン •

    インタラクティブシェルを操作して計算 • 値(あたい)とは SECTION 02
  24. Windows: PowershellでPythonを起動する • 「インタラクティブシェル」は対話形式でPythonを利⽤する操 作法で「REPL(Read Eval Print Loop)」やとも呼ばれる • Windows左下の検索ボックスに「powershell」と⼊⼒して

    PowerShell(コマンドラインアプリ)を起動 • Powershellで半⾓にて「python」と⼊⼒することで起動する • インストール時にパスを通し忘れていると「pythonというコマ ンドは存在しない」といった旨のエラー。再インストール。
  25. Mac: ターミナルでPythonを起動する(1/2) • ターミナルアプリケーションを開く

  26. Mac: ターミナルでPythonを起動する(2/2) • ターミナルで「python3」と⼊⼒して起動 • 注意: Macでは「python」と⼊⼒するとPython3ではなくデフォル トでインストールされているPython2が起動する。両者とも Pythonだが仕様(⽂法など)が⼤きくことなるので注意 •

    本資料ではWindowsを優先してpython表記とするが、python3と 読み替えること
  27. コラム: Pythonとバージョン • バージョン: Python X.Y という形式。Xがメジャーバージョン (Windows7, 10などのレベル)でYがマイナーバージョン(リリー ス時期やパッチなどのレベル)。

    • Python2: ⼀般普及した最初のメジャーバージョン。新規開発は 停⽌している。バージョン2で開発されたシステムのメンテ作 業は2020年代中盤あたりまでは継続することが予想される。⽇ 本語の扱いが苦⼿ • Python3: 現在普及しているメジャーバージョン。今から学ぶな らPython3をやるべき。新規開発も当然ながらPython3を使う • Python2と3は似ているが⽂法やライブラリが異なる別⾔語
  28. インタラクティブシェルで⾜し算、引き算 • インタラクティブシェルの挙動 1. 「>>>」に続けて実⾏したいことを書く 2. Enter(Return)キーを押す 3. Pythonが書かれていることを解釈する 4.

    Pythonが実⾏結果を画⾯に表⽰する 5. ステップ1に戻る $ python Python 3.8.2 (v3.8.2:7b3ab5921f, Feb 24 2020, 17:52:18) [Clang 6.0 (clang-600.0.57)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> 5 + 3 8 >>> 7 - 2 5 注意: MacはPython3コマンドで起動
  29. インタラクティブシェルで掛け算、割り算、剰余 • ⾜し算(+)引き算(-)は算数と同じ記号を使う • 掛け算には「*」記号を使う • 割り算には「/」記号を使う • 剰余(余り。たまに使う)では「%」記号を使う •

    算数と同じく⼩カッコ「()」で計算順序を調整できる >>> 4 * 4 16 >>> 7 / 2 3.5 >>> 31 % 2 1 >>> 5 + 2 * 3 11 >>> (5 + 2) * 3 21
  30. 値(あたい)とは • 「値(あたい)」はPythonが扱うデータのこと。英語ではvalue • たとえば数字の4や5 • たとえばテキスト(⽂字列と呼ばれる)のHello • 今後学ぶ様々な種類のデータも値

  31. • インタラクティブシェルを⽴ち上げて、「10 x 2」の計算を実 施してください • 「5 ÷ 2」の計算を実施してください •

    「5 + 2 * 2」と「(5 + 2) * 2」の計算結果の違いを確認し、な ぜ結果が異なるか説明してください • Python2とPython3の違いについて説明してください 演習
  32. 値を格納する「変数」を理解する • このセクションで学ぶこと • 変数と代⼊ • 変数の名前のつけかた • 複合代⼊演算⼦ •

    定数 SECTION 03
  33. 変数とは (1/3) • 「変数」は値を格納する容器 • 作成した変数に値をいれることを「代⼊」するという • 変数に代⼊された値は必要なときに⾃動で取り出される • 変数から値が取り出されてもなくならない

  34. 変数とは (2/3) • 変数を作成することを「宣⾔」するという • 「変数 = 値」という⽂法で変数の宣⾔と代⼊を同時におこなう。 (他のプログラミング⾔語では変数の宣⾔のみできるものもある が、Pythonでは宣⾔時に代⼊もおこなう)

    >>> abc = 51 >>> abc 51 >>> abc + 5 56 >>> abc + 10 61 変数abcを宣⾔し、51を代⼊ 変数abcから51が取り出されている 値が変数から取得されても中⾝はなくならない
  35. 変数とは (3/3) • 変数に新しい値を代⼊(「再代⼊」とよばれる)すると、古い値 は上書きされてなくなる • 変数Aに変数A(⾃分⾃⾝)や変数Bの値を代⼊することもできる >>> abc =

    51 >>> abc + 5 56 >>> abc = 8 >>> abc 8 >>> abc = abc + 3 >>> abc 11 すでに存在している変数に新しい値を代⼊(再代⼊) 変数が持つ値は新しい値で上書きされる 変数に変数の値を代⼊することもできる。 左は「abc = 8 + 3」と同じ意味
  36. 変数の⽤語 • 変数を作成すること => 「宣⾔」する • 変数に値をいれること => 「代⼊」する •

    すでに変数を持つ変数に値をいれること => 「再代⼊」する • 変数に値を代⼊する記号 => 「代⼊演算⼦」。「=」のこと • 変数から値を取り出すこと => 変数が値を「返す」 • これらの⽤語はプログラマの常識なので、知っていないと専⾨ 書籍を読んだりプログラマと会話する際に困ります。覚えて⾃ 分も使うことをおすすめします。
  37. 変数名の規則 • 変数に使える記号は「アルファベットと数字及びアンダーバー (_)」が基本。⽇本語も使えるがおすすめしない。 • 「必ずアルファベットから始まる」というルールがある • Pythonでは変数に⼤⽂字を使わないのが⼀般的 • 特別な意味を持つ予約後(たとえばforなど)は使えない

    • 変数名にはなにが⼊っているか分かりやすいものを使う >>> abc = 3 >>> 5ab = 3 File "<stdin>", line 1 5ab = 3 ^ SyntaxError: invalid syntax >>> price = 100 >>> text_length = 10 問題のある変数名はエラーとなる 上記のような分かりやすい名前が望ましい。 意味を持つ⼩⽂字英数字で単語の区切りを アンダーバーとするのが⼀般的なPythonの 変数の名付けかた。 この命名規則は「スネークケース」と呼ばれる
  38. 複合代⼊演算⼦ • 代⼊と演算(+や-)を同時にやる特殊な演算⼦は「複合代⼊演算 ⼦」と呼ばれる • 代⼊演算⼦の前に演算記号がつく。たとえば「+=」 • すでに代⼊されている変数を加⼯するためによく使われる • 変数に1を加えることを「インクリメント」と呼び、Pythonは

    それを複合代⼊演算⼦で実現する。「a += 1」 >>> a = 10 >>> a += 1 >>> a 11 >>> a -= 5 >>> a 6 複合代⼊演算⼦の例 同⼀の意味を持つ命令 a += 1 a = a + 1 a -= 5 a = a - 5 a *= 10 a = a * 10 a /= 3 a = a / 3
  39. 値の変わらない定数 • ⽬的の分からない値のことを「マジックナンバー」と呼ぶ • マジックナンバーやプログラムのパラメーター(たとえば処理を 何秒おきに呼び出すか)などは「定数」で宣⾔するのが⼀般的 • 定数は「⼤⽂字英数字とアンダーバーを使う」のが⼀般的 • プログラムファイル内で定数を使っているとパラメーター変更

    時のコード変更箇所を減らせる • 変数と異なり「定数は内部の値が変化しない」特徴がある >>> 100 * 1.08 108.0 >>> TAX_RATE = 1.08 >>> 100 * TAX_RATE 108.0 100に1.08をかけている理由が分からない。 これなに? 1.08が定数 TAX_RATE に代⼊されていると、 100に消費税 1.08 をかけていると⼀⽬瞭然。 宣⾔部を1.1に変えれば消費税率の変更にすぐ対応できる
  40. コラム: Pythonの定数 • 多くのプログラミング⾔語では定数に値を再代⼊するとエラー が発⽣する • Pythonでは定数に再代⼊してもエラーが発⽣しない • 実はPythonには⽂法としての定数はなく、ただの変数に過ぎな い。ただし、「⼤⽂字で宣⾔された変数は定数として使われ

    る」というのはPythonプログラマの常識なので再代⼊をするこ とは避ける必要がある。⼤⽂字の変数を定数として使う。
  41. • インタラクティブシェルを⽴ち上げて、変数abに5を代⼊し、 次に変数cdに10を代⼊し、最後に変数同⼠を⾜し算して結果を 確認してください • 変数aに10を代⼊し、それを複合代⼊演算⼦を使ったインクリ メントで11にしてください • 変数と定数の役割の違いについて説明してください •

    ⼀般的なPythonの変数名と定数名の命名ルールを説明してくだ さい 演習
  42. データの種類を決める「型」を理解する • このセクションで学ぶこと • ⽂字列 • データの種類と型 • 概念としての型と、実データとしての値 •

    関数(詳細は3章) • type関数で型を調べる⽅法 • キャストを使った型の変換⽅法 SECTION 04
  43. ⽂字列 • テキストデータは「⽂字列」と呼ばれる。⽂字が1つの字でそ れが列(複数)となるので⽂字列 • 1⽂字もない(空⽂字と呼ばれる)や1⽂字でも⽂字列と呼ばれる • ⽂字列は「シングルクオテーション(')」か「ダブルクオテー ション(")」でテキストを囲うことで宣⾔できる。Pythonではシ ングルクオテーションを使うのが⼀般的

    >>> a = 'h' >>> b = 'hello' >>> c = 'hello world' >>> d = "hello 123" >>> e = '' これらはすべて⽂字列
  44. ⽂字列の演算 • ⽂字列も数値と同じように演算できる • ただし⾜し算(結合)はできるが、引き算はできない • 数値の「123」と⽂字列の「'123'」はデータの種類が異なるの で同じではない >>> 'abc'

    + '123' 'abc123' >>> '123' + '456' '123456' >>> 123 + 456 579 >>> a = '123' >>> a += '456' >>> a '123456' >>> 456 - 123 333 >>> '456' - '123' Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unsupported operand type(s) for -: 'str' and 'str' ⽂字列の123は数値計算されていない
  45. ⽇本語の⽂字列 • Python3では⽇本語の⽂字列も使える。Python2は⽇本語が苦⼿ • アルファベットと異なり「⽂字コード(Shift-JISやUTF-8など)」 に気を配る必要がある • Python3のデフォルト⽂字コードはUTF-8なので「Pythonでは常 にUTF-8を使う」とルール化するのが⼀般的 •

    Shift-JISなどを含んだ⽇本語の詳細は7章で扱う $ python3 >>> 'あいうえお' + 'かきくけこ' 'あいうえおかきくけこ' $ python2 >>> 'あいうえお' + 'かきくけこ' '\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81 \x88\xe3\x81\x8a\xe3\x81\x8b\xe3\x81\x8d\xe3\ x81\x8f\xe3\x81\x91\xe3\x81\x93' MacでのPython3とPython2の⽇本語の扱い
  46. 概念とデータ - 型が持つ2つの性格 • 「123」と「'123'」の演算は異なる動きとなった。 • これは両者の値の「型(データの種類)」が異なるため • 型が「データの概念レベル」で値が「実際のデータ」 •

    どの型がどういった処理をできるか覚えるのがプログラミング の最初の⼀歩
  47. 関数 • 「受け取った値」にたいして「決められた処理」をおこない、 「結果を返す」仕組みをプログラミングでは「関数」と呼ぶ • 「結果を受け取る変数 = 関数名(関数に与える値)」という書式 で使うのが⼀般的 •

    関数に与える値のことを「引数」と呼び、関数から返される値 を「返り値」と呼ぶ • 関数の詳細は第3章で扱う >>> print(15) 15 >>> print('hello world') hello world print関数は与えられた値をコンソール出⼒する
  48. type関数を使った型の確認 • Pythonは「あまり型にうるさくない⾔語」 • メリット: 気軽にコーディングをおこなえる • デメリット: 変数に⼊っている型が想定していたものと違う といったトラブルがある

    • 「type 関数」を使うことで変数の型を確認できる • 拘束性は⾼くないが変数名に型を宣⾔することも可能(割愛) >>> a = 10 >>> type(a) <class 'int'> >>> a = 'hello' >>> type(a) <class 'str'> 数値を代⼊した変数aに⽂字列を再代⼊できる。 型にうるさい⾔語(C⾔語やJava)ではできない。 type関数に変数(そのなかの値)を与えると型がわかる。 intは「整数型」のこと
  49. キャストを使った型の変換(1/2) • プログラミングでは型を変換する場⾯が多々ある • たとえば「⽂字列型の値と整数型の値は結合できない」ので整 数型を⽂字列型に変換してから結合など • 型の変換のことを「キャスト」と呼ぶ >>> price

    = 100 >>> price + ' yen' Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unsupported operand type(s) for +: 'int' and 'str' 数値と⽂字列型の結合でエラーが発⽣
  50. キャストを使った型の変換(2/2) • ⽂字列型への変換には「str 関数」を使う • 整数型への変換には「int 関数」を使う • ⽂字列から数値へのキャストは変換できれば成功し、変換でき ない場合は失敗する

    >>> price = 100 >>> str(price) + ' yen' '100 yen' >>> int('100') 100 >>> int('hello') Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: invalid literal for int() with base 10: 'hello' 数値を⽂字列型にキャストしてから 別の⽂字列と結合 ⽂字列から数値へのキャストは失敗することがある
  51. コラム: シングルクオートとダブルクオート • ダブルクオートの⽂字列内ではシングルクオートが使え、シン グルクオートの⽂字列内ではダブルクオートが使える。 • そのため、以下の使い分けがおすすめ • 通常時: シングルクオート(Pythonでは⼀般的なため)

    • ⽂字列内にシングルクオートを持つ場合: ダブルクオート • エスケープシーケンス(後述)を使うことでシングルクオートの ⽂字列内でシングルクオートを使うこともできる。ダブルク オートも同様 >>> 'hello I'm Taro' File "<stdin>", line 1 'hello I'm Taro' ^ SyntaxError: invalid syntax >>> "hello I'm Taro" "hello I'm Taro" >>> 'hello I\'m Taro' "hello I'm Taro" >>>
  52. • 値「123」と値「'123'」の違いを説明してください • 「'123' + '123'」の結果がどうなるか確認し、キャストを使っ て結果が246になるように式を変更してください • 数値「1.1」の型をtype関数で確認してください 演習

  53. 制御構⽂を理解しよう CHAPTER 2 1. プログラムファイルを作って実⾏する 2. 条件分岐の仕組みを理解する 3. ループ処理で繰り返しを記述する

  54. プログラムファイルを作って実⾏する • このセクションで学ぶこと • IDLE(標準の統合開発環境)の起動⽅法 • 新規ファイルの作成と保存⽅法 • IDLEでのプログラムの実⾏⽅法 •

    わざとエラーを発⽣させてエラー内容を読む • コメント • コンソールからプログラムを実⾏ • コラム: 複数⾏にわたる⽂字列 SECTION 01
  55. IDLE(統合開発環境)の起動 • Pythonをインストールするとには「IDLE」という統合開発環 境も同時にインストールされている • Windows: スタートメニューから選択(以下の図)して起動 • Mac: アプリケーションのディレクトリから起動

  56. IDLEで新規ファイルを開く • IDLEのメニューは英語表記だが操作は単純 • プログラムを開発するために図の⼿順で新規ファイルを開く • 新規ファイルを開くとエディタの画⾯が現れる • 既存のファイルを開くこともできる。以下の図の「Open..」

  57. IDLEでファイルを保存する • エディタに以下のプログラム(スライド5PめのURLより以後の プログラム全てをダウンロード可能)を記述する • メニューバーから保存操作(図を参照)する • 保存する場所は「デスクトップ上のpythonフォルダ」とし、そ こに「test_01.py」という名前で保存 print(1)

    print('2') a = 1 + 2 print(a) /chapter2/test_01.py
  58. IDLEでプログラムを実⾏ • IDLEのプログラムのエディタを選択(クリックして前⾯に) • 以下のいずれかの⽅法で実⾏ • メニューバーの「<Run> -> <Run Module>」

    • F5ボタン(MacだとFnボタンを押しながら)を押す • インタラクティブシェルと異なりprint関数などで意図的に出⼒ させないとどのような動きをしているか⾒えない
  59. エラーを発⽣させて確認する • プログラムを開発していると、勘違いや⼊⼒ミスで必ずエラー は発⽣する • エラーを特定して問題箇所の修正を繰り返すことでプログラム はきちんと動作するようになる • わざとエラーを発⽣させてエラーの読み⽅を確認してみる print(1)

    print('2') a = 1 + 2 print(b) 1 2 Traceback (most recent call last): File "/Users/yuichi/Desktop/python/test_02.py", line 4, in <module> print(b) NameError: name 'b' is not defined エラーメッセージから「どのファイル(test_02.py)」の 「どの⾏(line 4)」で 「どのような問題(NameError: name ʻbʼ is not defined)」が おきているかわかる /chapter2/test_02.py コンソール出⼒
  60. コメント • 「コメント」: プログラム中の実⾏されない特別なテキスト • プログラムの説明(なにをしているか注釈)に利⽤したり、実⾏ してほしくない箇所をコメント化する使い⽅が⼀般的 • コメントの⽅法 •

    「#(シャープではなくハッシュと読む)」の後ろ(1⾏) • 「'''」もしくは「"""」で囲まれた複数⾏のテキスト #print(1) print('2') ''' a = 1 + 2 print(b) ''' 2 /chapter2/test_03.py コンソール出⼒ コメントした箇所が実⾏されていないので、 コンソール出⼒されていないことがわかる。 さきほどのエラー箇所も無視されている。 プログラムをコメント化することを 「コメントアウト」という
  61. コンソールからプログラムを実⾏ • Pythonのプログラムはコンソール(Powershellやターミナル)か ら実⾏できる。 • プログラムファイルを指定してpythonコマンドで呼び出す • 本格的な開発ではプログラミング⽤エディタ(VSCodeなど)で 開発してコンソール実⾏するか、IDLEより⾼度な IDE(PyCharmなど)の利⽤が⼀般的

    PS C:\Users\yito> cd ~/Desktop/python PS C:\Users\yito\Desktop\python> python test_01.py 1 2 3 $ cd ~/Desktop/python $ python3 test_01.py 1 2 3 Windowsの例 Macの例 (python3コマンド)
  62. コラム: 複数⾏にわたる⽂字列 • 「トリプルクオテーション(''')」を使った複数⾏のコメントア ウトは厳密には「囲んだ箇所を⽂字列化」している • 純粋な複数⾏のコメントアウトの⽂法はない • ⽂字列化でのコメントアウトに問題がある場合はすべての⾏に 「#」をつけてコメントアウトする

    text = '''hello world python''' print(text) $ python3 multi_line_string.py hello world python /chapter2/multi_line_string.py コンソール出⼒
  63. コラム: エスケープシーケンス • 改⾏やタブといった特殊⽂字を使う場合は「エスケープシーケ ンス」を使う • エスケープシーケンスは半⾓バックスラッシュ「\」(⽇本語 キーボードだと半⾓「\」記号)に続けて特定の1⽂字を書く • よく使うエスケープシーケンス

    • 改⾏: \n • タブ: \t • シングルクオテーション: \' • ダブルクオテーション: \" >>> print('hello\nworld') hello world エスケープシーケンス「\n」で 改⾏されている
  64. • IDLEを起動して以下のプログラム(1)を新規作成して実⾏ • プログラミング⽤エディタ(好みがなければVSCodeをインス トール)で以下のプログラム(1)を作成して、コンソールで実⾏ • インタプリタで以下の出⼒(2)をする • コメントの利⽤⽤途を2つ以上説明する 演習

    print('I love Python') I will complete this training プログラム(1) 出⼒(2)
  65. 条件分岐の仕組みを理解する • このセクションで学ぶこと • 絶対値を求めるabs関数 • abs関数の条件分岐 • if⽂を使った条件分岐 •

    インデントによるコードブロック • Bool型 • ⽐較演算⼦ • Bool値を扱う演算⼦ • 複雑なif⽂ SECTION 02
  66. 絶対値を求めるabs関数 • 絶対値はある数値(マイナスも含む)の0からの距離 • 「変化の⼤きさ」を表現するのに使われる • Pythonでは「abs関数」を使うことで絶対値を求められる >>> abs(5) 5

    >>> abs(-10) 10 >>> abs(0) 0 インタプリタでのabs関数の確認
  67. abs関数の条件分岐 • 「条件分岐」は「ある特定の条件を満たす場合のみ、何かの処 理をする」という仕組み • 絶対値を得る条件分岐は 「値(変数aとする)が0より⼤きいとい う条件」を満たす場合のみ「値に-1をかけてプラスにする」と いう処理をする abs関数の条件分岐

  68. if⽂を使った条件分岐 • Pythonで条件分岐を使うには「if」を使う • ifに続けて「条件式(TrueかFalseが得られる式)」を書く • 次の⾏以降でインデント(字下げ)して処理を書く • 注意: 他のプログラミング⾔語のようにifのあとに()で条件式を

    囲んでも問題ないが、Pythonでは囲まないのが⼀般的 a = -5 if a < 0: a = a * -1 print(a) if 条件式: 条件式を満たす場合の処理 /chapter2/abs_01.py $ python3 abs_01.py 5 コンソール出⼒ If⽂の⽂法
  69. インデントによるコードブロック • 「コードブロック」はプログラムの制御処理の対象範囲のこと • 何⾏⽬から何⾏⽬までをコードブロックとするかはインデント による字下げで表現する • Pythonでは半⾓4つが標準的なインデントでタブは⾮推奨(1つ のプログラム中で空⽩とタブの字下げを混在させるとエラー) •

    プログラミング⽤エディタはタブを半⾓に⾃動変換するものも ある a = -5 if a < 0: print(1) print(2) a = a * -1 print(3) print(a) $ python3 abs_02.py 1 2 3 5 /chapter2/abs_02.py コンソール出⼒ インデント (字下げ)は 半⾓4つが標準
  70. Bool型 • 条件を満たす/満たさないを表現する型。条件分岐などに使う • 「True」と「False」の2値しかない • 「条件を満たす」は「条件式がTrueを返す」こと • 「条件を満たさない」は「条件式がFalseを返す」こと >>>

    5 > 3 True >>> 5 < 3 False a = -5 if a < 0: a = a * -1 print(a) /chapter2/abs_01.py インタプリタでの確認
  71. ⽐較演算⼦ (1/2) • True/Falseを得るための演算⼦ • 制御構⽂の条件式などでよく利⽤される • 数字以外でも⽂字列などでも使える 演算⼦ 意味

    使⽤例(Trueの場合) == 左辺と右辺が等しいときにTrueを返す 20 == 20 != 左辺と右辺が等しくないときにTrueを返す 20 != 30 > 左辺が右辺より⼤きいときにTrueを返す 30 > 20 >= 左辺が右辺以上のときにTrueを返す 30 >= 20, 30 >= 30 < 左辺が右辺より⼩さいときにTrueを返す 20 < 30 <= 左辺が右辺以下のときにTrueを返す 20 <= 30, 20 <= 20
  72. ⽐較演算⼦ (2/2) • 異なる型での⽐較などもできる • ⽂字列の⽐較などはCやJavaと挙動が異なるので注意(Pythonは ポインタではなく値で⽐較するので分かりやすい) >>> 4 ==

    4.0 True >>> 4 == '4' False >>> 'abc' > 'def' False >>> 'hello' == 'hello' True >>> 'hello' == ('hel' + 'lo') True コンソール出⼒ ⽂字列の⽐較はユニコードの 順番で決まっている。 aはdより前にあるので⼩さい
  73. Bool値を扱う演算⼦ • 条件式ではBool値の反転や「かつ」「または」などもよく使う • 「and」演算⼦: 左辺と右辺の値がともにTrueの時にTrueを返す • 「or」演算⼦: 左辺と右辺の値のどちらかがTrueの時にTrueを返す •

    「not」演算⼦: True/Falseを逆転させる >>> True and True True >>> True and False False >>> True or True True >>> True or False True >>> not True False >>> not False True and演算⼦の確認 or演算⼦の確認 not演算⼦の確認
  74. 複雑なif⽂ • 「elif」は 前⽅のifかelifに合致しなかったときに条件チェック される分岐。好きなだけ繰り返せる • 「else」は前⽅のifとelifの全てに合致しなかったときに呼び出 される処理を書く a =

    15 if a % 2 == 0: print('2') elif a % 3 == 0: print('3') elif a % 5 == 0: print('5') else: print('nothing') $ python3 if_elif_else.py 3 /chapter2/if_elif_else.py コンソール出⼒
  75. • 有名なFizzBuzz問題のプログラムを作成する • 変数 a に整数を任意の数を与える • 変数 a が3で割り切れれば「Fizz」と出⼒

    • 変数 a が5で割り切れれば「Buzz」と出⼒ • 変数 a が3でも5でも割り切れれば「FizzBuzz」と出⼒ • ヒント: 「1章で学んだ剰余で余りが0になること」が「割り 切れる」ということ • 変数aを様々な値に変更して挙動を確認してください 演習
  76. ループ処理で繰り返しを記述する • このセクションで学ぶこと • リストのデータを準備する • リストのデータを取り出す • リストのデータを上書きする •

    リスト⻑を取得する • リストのデータをまとめて処理するforループ • Breakによるループ打ち切り • Continueによるループの周回スキップ • Continueの便利な利⽤法 • 条件が満たされる間はループを繰り返すwhile⽂ SECTION 03
  77. リストのデータを準備する • Pythonのループでは「リスト型」の値をよくつかう • リスト型は⼀覧(リスト)となっているデータを扱うための型 • 「要素」はリストの中⾝のデータ(数値や⽂字列など)のこと • リストの要素には順序がある >>>

    ['taro', 'jiro', 'saburo'] ['taro', 'jiro', 'saburo'] >>> [] [] >>> a = ['taro', 'jiro', 'saburo'] >>> print(a) ['taro', 'jiro', 'saburo'] >>> リストの宣⾔は⼤かっこ([])に要素を並べる 要素がひとつもない場合は[]のみ リスト内の要素の順序は保たれる
  78. リストのデータを取り出す • リスト内のデータは前⽅から0,1,2と数える。1からではなく0か ら数え始めるので注意 • 要素の順番のことを「インデックス番号」と呼ぶ • 「リスト[インデックス番号]」とすると、指定したインデック ス番号の要素が取り出される。取り出されてもなくならない >>>

    a = ['taro', 'jiro', 'saburo', 10] >>> a[0] 'taro' >>> a[2] 'saburo' リスト要素の取得
  79. リストのデータを上書きする • 「リスト[インデックス番号] = 代⼊する値」という形式でイン デックス番号を指定して要素に代⼊することもできる • リストの⻑さを超えたインデックスの参照は取得でも代⼊でも エラーとなる >>>

    a = ['taro', 'jiro', 'saburo', 10] >>> a[1] = 'hanako' >>> a[3] = 'adam' >>> print(a) ['taro', 'hanako', 'saburo', 'adam'] 存在しないインデックスの参照はエラーとなる >>> a = ['taro', 'jiro', 'saburo', 10] >>> a[4] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list index out of range >>> a[4] = 100 Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list assignment index out of range リストの要素をインデックスで指定して代⼊すると その要素が代⼊値で上書きされる
  80. リスト⻑を取得する • リスト⻑: リストの要素の数のこと • 「len関数」でリスト⻑を取得できる • 「len関数の取得値-1までインデックスでアクセスができる」と 覚えておく >>>

    a = ['taro', 'jiro', 'saburo', 10] >>> len(a) 4 >>> a[3] 10 >>> a[4] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list index out of range len関数の確認と要素へのアクセス len関数の取得値でアクセス 可能なインデックス値の最⼤値が わかる
  81. リストのデータをまとめて処理するforループ • リストに代表される「シーケンス(連なりのあるデータ)」構造 • 「for」ループでシーケンスを前から後ろに順番に処理できる name_list = ['taro', 'jiro', 'saburo',

    'shiro', 'goro'] for name in name_list: print(name) $ python3 forloop.py taro jiro saburo shiro goro for 変数 in シーケンス: 処理 /chapter2/forloop.py コンソール出⼒ for⽂の⽂法 ループするごとにシーケンスの要素を前から後ろに変数に代⼊する シーケンスの最後までたどり着くとループが終了 ブロックの使い⽅はifと同じ
  82. breakによるループ打ち切り • 「break」命令でループ処理を打ち切る • ループを継続する理由がなくなった場合に利⽤される • 例: 整数のリスト中に偶数があるかをチェック。(偶数を⾒つけ たら残りのリストの要素はチェック不要なのでbreak) a

    = [5, 9, 11, 3, 6, 5, 11, 4, 9] has_even = False for i in a: print('checking: ' + str(i)) if i % 2 == 0: has_even = True break print('has even: ' + str(has_even)) $ python3 forloop_break.py checking: 5 checking: 9 checking: 11 checking: 3 checking: 6 has even: True /chapter2/forloop_break.py コンソール出⼒ リストの6より後ろはbreakされたので 出⼒されていない
  83. continueによるループの周回スキップ • 「continue」命令で ループのそのその回だけを抜ける • ループ⾃体は継続するのでシーケンスの次の要素は処理する • 要素が「特定条件を満たす場合のみだけ処理する」際に continueを使うとよい a

    = [5, 9, 11, 3, 6, 5, 11, 4, 9] for i in a: if i % 2 == 1: continue print('Even: ' + str(i)) $ python3 forloop_continue_01.py Even: 6 Even: 4 /chapter2/forloop_continue_01.py コンソール出⼒
  84. continueの便利な利⽤版 • breakの利⽤難易度は低いが、continueは使い慣れない⼈が多い • ループでの条件分岐のインデント階層を減らすのに便利 for i in a: if

    条件1: if 条件2: if 条件3: 処理 for i in a: if 条件1: continue if 条件2: continue if 条件3: continue 処理 Continueなし Continueあり
  85. 条件が満たされる間はループを繰り返すwhile⽂ • 「while」ループで条件式が満たされる限り繰り返す • 他のプログラミング⾔語ではwhileは多⽤されるが、Pythonで はforループを可能な限り使うこと。forが使えない場合にwhile ⽂を検討する a = [5,

    9, 11, 3] length = len(a) i = 0 while i < length: print('index ' + str(i) + ' : ' + str(a[i])) i += 1 $ python3 while_loop.py index 0 : 5 index 1 : 9 index 2 : 11 index 3 : 3 /chapter2/while_loop.py コンソール出⼒ while 条件式: 処理 while⽂の⽂法 条件式がTrueとなる限りループを継続する ブロックの使い⽅はifやforと同じ
  86. • Forループで以下の⾝⻑の平均値、最⼤値、最⼩値を求めてく ださい。ヒント: 合計値と最⼤値と最⼩値のそれぞれの変数を ループ前に定義して、ループを回るたびにその値を更新する • 180cm • 170cm •

    160cm • 165cm • 175cm • 余裕がある⼈は10進数を2進数(⽂字列)に変換するプログラム をwhileループで作成してください。検索するとアルゴリズム がでてくるはずです。2進数は⽂字列の複合代⼊演算⼦(結合)で 作成してください。 演習
  87. 関数の使い⽅をマスターしよう CHAPTER 3 1. なぜ関数が必要なのか? 2. オリジナルの関数を定義する 3. 関数の引数と返り値を⾃在に操る 4.

    名前空間と関数型について知る 5. 組み込み関数を活⽤する
  88. なぜ関数が必要なのか? • このセクションで学ぶこと • 関数にしかできない処理を提供する • 複雑な処理を簡単に実現する • コードの重複の排除 SECTION

    01
  89. 役割(1) - 関数にしかできない処理を提供する • OSやハードウェアの機能(画⾯出⼒やネットワークなど)の利⽤ は関数しかできない • 関数の内部ではシステムコールなどにより低いレイヤのプログ ラム(C⾔語)が呼び出されている

  90. 役割(2) - 複雑な処理を簡単に実現する(1/3) • アルゴリズムを⾃分で書けば複雑な処理も実現できる • ⼀般的な処理はPythonが関数などを提供しているので、それを 使うほうが「簡単」「バグが少ない」「速い」 例: リストの要素のソートの実装

    選択ソートというアルゴリズム 1. リストの最⼩値を探す 2. 0番⽬の要素とスワップ 3. 1番⽬以降で最⼩値を探す 4. 1番⽬の要素とスワップ 5. … 6. 要素の最後までたどり着けばソート終了 変数間の値の交換は ⼀時的な変数が必要
  91. 役割(2) - 複雑な処理を簡単に実現する(2/3) • 現時点の知識でのソートアル ゴリズムの実装(難しい) • 変数の値の交換処理には⼀時 変数が必要 a

    = [5,9,4,1,8] length = len(a) i = 0 while(i < length): # i番⽬以降の最⼩の要素を探す minimum_index = i j = i + 1 while j < length: if a[j] < a[minimum_index]: minimum_index = j j += 1 # i番⽬と最⼩の要素をスワップする if minimum_index != i: tmp = a[i] a[i] = a[minimum_index] a[minimum_index] = tmp # i番⽬のループが終わった際のリスト print(str(i) + ': ' + str(a)) i += 1 print('sorted: ' + str(a)) $ python3 sort_list_01.py 0: [1, 9, 4, 5, 8] 1: [1, 4, 9, 5, 8] 2: [1, 4, 5, 9, 8] 3: [1, 4, 5, 8, 9] 4: [1, 4, 5, 8, 9] sorted: [1, 4, 5, 8, 9] コンソール出⼒ /chapter3/sort_list_01.py
  92. 役割(2) - 複雑な処理を簡単に実現する(3/3) • sorted関数で昇順ソート(⼩さいものから⼤きいものへ)が提供さ れている • ⾃作のソート処理より以下の点で優れる • プログラムの⾒た⽬がシンプル

    • ⾼速(選択ソートより賢いアルゴリズムがC⾔語で実装される) • バグが発⽣する可能性が低い a = [5,9,4,1,8] b = sorted(a) print(b) $ python3 sort_list_02.py [1, 4, 5, 8, 9] コンソール出⼒ /chapter3/sort_list_02.py ⾃作の20⾏以上のプログラムがたった1つの 関数呼び出しに置き換えられた
  93. 役割(3) - コードの重複の排除 • 同⼀の処理をコピーペーストで何度も書くのはよくない • ソースコードが無駄に⻑くなって読みにくくなる • バグやコードの修正が発⽣すると⾯倒だしトラブルのもと •

    関数化されていれば「⾒やすい」し「変更(修正)しやすい」 a = 5 if a < 0: a *= -1 # 何か関係ない処理 b = -3 if b < 0: b *= -1 print(a) # 5 print(b) # 3 a = 5 a = abs(a) # 何か関係ない処理 b = -3 b = abs(b) print(a) # 5 print(b) # 3 /chapter3/get_abs_01.py /chapter3/get_abs_02.py
  94. • 関数が必要な理由を3つ説明してください • 発展課題: ソートアルゴリズムについて調査し、バブルソート を実装してください 演習

  95. オリジナルの関数を定義する • このセクションで学ぶこと • 関数の概念の復習 • 関数を定義する • ⾃分で定義した関数を利⽤する •

    関数の命名ルール • 定義と参照の順序 SECTION 02
  96. 関数の概念の復習 • 関数の仕事 1. 「引数」でデータを受け取る 2. 受け取ったデータで処理を⾏う 3. 結果を「返り値」として呼び出し元に返す •

    絶対値を求めるabs関数の例 1. 引数で数値を受け取る 2. 受け取った数値を絶対値にする(マイナスであればプラス に変換する) 3. 絶対値を呼び出し元に返す 処理 (絶対値の算出) 引数による⼊⼒(数値) 返り値による出⼒(絶対値) 関数
  97. 関数を定義する • 関数を定義する⽂法ルールがある • 引数は関数内で変数として利⽤される。再代⼊も可能 def my_abs(x): if x <

    0: x *= -1 return x def 関数名(引数1, 引数2, ...): 処理1 処理2 return 返り値 絶対値を求める関数の定義例 • 関数名: my_abs • 引数: x • 処理: if⽂でxを絶対値にする • 返り値: 処理されたx /chapter3/define_function_02.py 関数を実装する⽂法 「return⽂」で呼び出し元に値を返す 「def⽂」で関数呼び出しの定義 • 関数名 • 引数 処理は関数のブロックで定義する
  98. ⾃分で定義した関数を利⽤する • ⾃作関数の利⽤法はPythonが提供する関数(printなど)と同じ • 関数名に()をつけ、引数として渡す値や変数を()内に並べる • 関数の定義より前で関数を呼び出すとエラーになる def my_abs(x): if

    x < 0: x *= -1 return x a = my_abs(3) print(a) print(my_abs(-5)) print(my_abs(-5)) def my_abs(x): if x < 0: x *= -1 return x $ python3 define_function_04.py Traceback (most recent call last): File "define_function_04.py", line 1, in <module> print(my_abs(-5)) NameError: name 'my_abs' is not defined $ python3 define_function_03.py 3 5 コンソール出⼒ コンソール出⼒ /chapter3/define_function_03.py /chapter3/define_function_04.py 呼び出し側で渡した引数3が 関数側の引数xに代⼊される。 引数の数は同じにすること returnの 返り値が 戻される
  99. 関数の命名ルール • 関数名の⽂法的なルールは変数名と同じ • アルファベットの⼩⽂字と数字をアンダーバーで区切る • ⼤⽂字の利⽤も可能だがPythonらしくない名前 • 「関数名は動詞から始める」というのが⼀般的なルール def

    add_something(x): ... def get_something(x): ... def something_adder(x): ... def something_getter(x): ... def addSomething(x): ... def getSomething(x): ... よい変数名の例 Pythonらしくない変数名の例
  100. コラム: 変数の定義と参照の順序 • 関数と同様に変数も「定義前に参照するとエラー」となる • プログラムがどのような流れで読み込まれて処理されるかを意 識すればトラブルを避けやすい print(a) a =

    5 $ python3 define_variable.py Traceback (most recent call last): File "define_variable.py", line 1, in <module> print(a) NameError: name 'a' is not defined コンソール出⼒ /chapter3/define_variable.py
  101. • FizzBuzz問題を関数化してください • FizzBuzz⾃体の説明は2章の演習を参照してください • 引数は1つで整数を受け取ります • 返り値は「 " Fizz

    " 」「 " Buzz " 」「 " FizzBuzz " 」「 " " 」のいずれかの⽂字列とします • forループで「0から20までリストの各要素」にたいして FizzBuzzの関数を使い、結果を1つずつprintしてください • 数値を受け取り、その数値が偶数であればTrue, 奇数であれば Falseを返す is_even 関数を作成してください。ヒント: 偶数と 奇数の判定は2で割り切れるかを剰余計算(%記号)で求める 演習
  102. 関数の引数と返り値を⾃在に操る • このセクションで学ぶこと • 返り値の有無によるコードの違い • 複数のreturn⽂を記述する • 関数に複数の引数を定義する •

    キーワード引数を定義する • デフォルト引数 • 可変⻑引数を利⽤する • コラム: help関数で関数の詳細を確認する SECTION 03
  103. 返り値の有無によるコードの違い • returnが定義されていないと「None(何もないという値)」を返す • returnに変数や値が与えられていないときもNoneを返す • 「Noneを返す」ということは「関数の返り値がない」と同じ意味 def my_print1(x): print('my

    print1: ' + str(x)) def my_print2(x): print('my print2: ' + str(x)) return a = my_print1(5) print(a) b = my_print2(5) print(b) $ python3 return_value_01.py my print1: 5 None my print2: 5 None コンソール出⼒ /chapter3/return_value_01.py
  104. 複数のreturn⽂を記述する • 関数にreturnを複数定義することができる • returnが呼び出されたら関数の処理はそこで終わる。後ろに処 理が残っていようとループ中であろうと残る処理はスキップさ れる def my_abs(x): if

    x > 0: return x print('less than 0') return x * -1 print(my_abs(5)) print(my_abs(-5)) $ python3 return_value_02.py 5 less than 0 5 コンソール出⼒ /chapter3/return_value_02.py
  105. 関数に複数の引数を定義する • 関数の引数は好きな数だけ使うことができる • 引数を受け取らない関数は引数を定義しない • 「定義した引数の数」と「呼び出し時の引数の数」が異なると エラーが発⽣ def fun0():

    print('fun0') def fun1(arg1): print('fun1') def fun5(arg1, arg2, arg3, arg4, arg5): print('fun5: arg1 is ' + arg1) fun0() fun1(1) fun5('a', 'b', 'c', 'd', 'e') $ python3 return_value_03.py fun0 fun1 fun5: arg1 is a コンソール出⼒ /chapter3/return_value_03.py
  106. キーワード引数を定義する • 今まで利⽤してきた引数は正式には「位置引数」と呼ばれる。定 義された引数の「順序」通りに引数を与える使い⽅ • 「キーワード引数」は 定義された引数名を指定して引数を与える • 引数の数が多い場合はキーワード引数だと順番間違いがない def

    test(arg1, arg2, arg3): print(str(arg1) + str(arg2) + str(arg3)) # 位置引数 test(1, 2, 3) # キーワード引数 test(arg2='a', arg1='b', arg3='c') $ python3 keyword_argument_01.py 123 bac コンソール出⼒ /chapter3/keyword_argument_01.py 関数定義の引数名を指定して 値を渡している
  107. デフォルト引数 • 「デフォルト引数」で引数にデフォルト値を定義できる • キーワード引数とともに利⽤されることが多く、関数呼び出し 時に対象となる引数を与えないとデフォルト値が使われる • デフォルト引数の後ろにデフォルト引数を持たない引数は定義 できない。⽂法エラーが発⽣する def

    test(arg1, arg2=2, arg3=3): print(str(arg1) + str(arg2) + str(arg3)) test(1, 'B', 'C') test(1) test(1, arg3='C') $ python3 keyword_argument_02.py 1BC 123 12C コンソール出⼒ /chapter3/keyword_argument_02.py
  108. 可変⻑引数を利⽤する • 与える引数が固定でない関数の引数を「可変⻑引数」と呼ぶ • 可変⻑引数を⾃分で定義するのは初⼼者向けではないが、既存 関数で使う場⾯は多いので使いかたは知っておくこと • 「スプラット演算⼦(*)」を使うとリストを可変⻑引数に使える print('hello') print('hello',

    'python') print(1, 2, 3, 4, 5, 6, 7, 8, 9) $ python3 variable_arguments_01.py hello hello python 1 2 3 4 5 6 7 8 9 print([1, 2, 3, 4, 5, 6, 7, 8, 9]) print(*[1, 2, 3, 4, 5, 6, 7, 8, 9]) $ python3 variable_arguments_02.py [1, 2, 3, 4, 5, 6, 7, 8, 9] 1 2 3 4 5 6 7 8 9 コンソール出⼒ コンソール出⼒ /chapter3/variable_arguments_01.py /chapter3/variable_arguments_02.py
  109. コラム: help関数で関数の詳細を確認する • 「help関数」の引数に関数名をあたえることで、その関数の詳 細を確認することができる • 引数などを忘れた場合にインタプリタですぐに確認できる >>> help(print) Help

    on built-in function print in module builtins: print(...) print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False) Prints the values to a stream, or to sys.stdout by default. Optional keyword arguments: file: a file-like object (stream); defaults to the current sys.stdout. sep: string inserted between values, default a space. end: string appended after the last value, default a newline. flush: whether to forcibly flush the stream. help関数を使ったprint関数の詳細確認
  110. • None型の値と型名をtype関数で調べてください • 先に作成したmyabs関数を「ifブロック内でマイナスをプラス に戻した値をreturnで返す」ように変更してください • 2つの引数を受け取り、⼤きい側の引数を返すmymax関数を作 成してください • mymax関数をキーワード引数で呼び出してください

    • help関数で今まで学んだPython標準の関数のなにかを調べてく ださい 演習
  111. 名前空間と関数型について知る • このセクションで学ぶこと • 関数の中にある変数の扱い • global宣⾔ • 名前空間 •

    関数型 • 関数を受け取る関数 SECTION 04
  112. 関数の中にある変数の扱い (1/2) • 関数の外では関数内で定義された変数を使えない(アクセスでき ない) • アクセスできない変数を参照しようとするとエラーが発⽣ def test(x): y

    = x + 1 return y print(test(5)) print(y) $ python3 name_space_02.py 6 Traceback (most recent call last): File "name_space_02.py", line 6, in <module> print(y) NameError: name 'y' is not defined コンソール出⼒ /chapter3/name_space_02.py
  113. 関数の中にある変数の扱い (2/2) • 関数の外で定義された変数は、関数内でも参照できる • 関数内で関数外の変数を上書きしても、関数外の変数の値は変 わらない(厳密には関数内部に同じ名前の変数が定義され、それ に代⼊されているという動きをしている) a =

    1 def test(): print(a) test() $ python3 name_space_03.py 1 a = 1 def test(): a = 10 test() print(a) $ python3 test1.py 1 コンソール出⼒ コンソール出⼒ /chapter3/name_space_03.py test1.py
  114. global宣⾔ • 「グローバル宣⾔(global)」を変数にすることで、関数外の変 数を関数内で上書きできるようになる • グローバル宣⾔の利⽤は⾮推奨。関数外の変数を上書きしたい のであれば、関数の返り値を変数に再代⼊するのが⼀般的 a = 1

    def test(): global a a = 10 test() print(a) $ python3 name_space_04.py 10 コンソール出⼒ /chapter3/name_space_04.py
  115. 名前空間 (1/2) • 変数を参照できるスコープ(エリア)を「名前空間」と呼ぶ • 基本的には「中から外の変数は参照できる」「中で外の変数に 代⼊しない」「外から中の変数は参照できない」と覚えておく 名前空間のまとめ図 細かいですが理解してください

  116. 名前空間 (2/2) • 名前空間を使う鉄則(中級者向けトピック) • どこからでも参照できる変数は「どこでどういった操作が⾏ われるか」管理しにくく、バグになりやすい • あえて変数が利⽤できる範囲を狭めることで、その変数の使 いみちを分かりやすくし、変な状態にならないようにする

    • 「グローバル変数(どのブロックにも属さない⼀番上のレベ ルの変数)」は可能な限り利⽤しないようにして、関数内の 変数やクラスで定義された変数(5章)を使うこと
  117. 関数型 • Pythonの関数も「関数型(概念)」の値(具体的なデータ) • print関数は関数型の値の1つであり、len関数も同様 • type関数に関数を与えることで関数型である確認ができる • 関数型の値は変数に代⼊でき、変数経由で関数を呼び出せる。 上級者向けのプログラミングテクニックでよく使う

    >>> type(abs) <class 'builtin_function_or_method'> >>> def my_abs(x): ... if x < 0: ... x *= -1 ... return x ... >>> type(my_abs) <class 'function'> >>> fun = abs >>> fun(-5) 5 コンソール出⼒ 組み込み関数と⾃作関数の型の確認。厳密には違うが区別しなくてよい
  118. 関数を受け取る関数 • 関数Aの引数として関数Bを渡す場合がある。関数Aの挙動を関 数Bで調整する。関数を受け取る関数を「⾼階関数」と呼ぶ。 • たとえばソートの基準を関数として定義し、その基準通りに ソートを実施するなど a = [5,

    -7, 0, 9, -3] print(sorted(a)) a = [5, -7, 0, 9, -3] def my_abs(x): if x < 0: x *= -1 return x print(sorted(a, key=my_abs)) $ python3 sort_argument_01.py [-7, -3, 0, 5, 9] $ python3 sort_argument_02.py [0, -3, 5, -7, 9] コンソール出⼒ コンソール出⼒ /chapter3/sort_argument_01.py /chapter3/sort_argument_02.py keyはキーワード引数(デフォルト付き)の指定
  119. コラム: 制御構⽂の名前空間 • Pythonではifやforなどの制御⽂のブロックで宣⾔した変数は、 そのブロック外でも参照できる • 他のプログラミング⾔語では参照できないものが多いので注意 def fun(x): if

    x == 1: y = 5 else: y = 10 print(y) fun(1) $ python3 test.py 5 test.py コンソール出⼒ 変数yは条件分岐の構⽂内で宣⾔されているので、 print⽂があるブロック(関数)より内側にある。 問題なくアクセスできている
  120. • Pythonの名前空間の動きを説明してください • 関数内から関数外の変数のアクセス • 関数外から関数内の変数のアクセス • global宣⾔の効果 • なぜglobal宣⾔が推奨されないか

    • 関数で関数外の変数を更新したいときはどのような関数とす るのが望ましいか • sorted関数に⾃作関数を渡して降順ソート(⼤きいものから ⼩さいものへ)を実現してください 演習
  121. 組み込み関数を活⽤する • このセクションで学ぶこと • for⽂で便利なrange関数 • リストを扱うのに便利な関数 • filter関数でリストの要素を絞り込む •

    map関数でリストをまとめて処理する SECTION 05
  122. for⽂で便利なrange関数 • 「range関数」で数字の連番(0,1,2...など)を作れる • 利⽤法1: 引数を1つ与えて0からその値-1までの連番を作る • 利⽤法2: 引数を1つ与えて「1つめの引数の値」から「2つめの 引数の値

    - 1」までの連番を作る • 「N回ループする」ときにfor⽂と利⽤法1の組み合わせが便利 a = range(5) print(a) print(list(a)) for i in range(2,5): print(i) $ python3 range_01.py range(0, 5) [0, 1, 2, 3, 4] $ python3 range_02.py 2 3 4 コンソール出⼒ コンソール出⼒ /chapter3/range_02.py /chapter3/range_01.py
  123. リストを扱うのに便利な関数 • len関数: リスト⻑さの取得 • max関数: 引数の最⼤値を取得。引数はリストか可変⻑引数 • min関数: 引数の最⼩値を取得。引数はリストか可変⻑引数

    list1 = [4, 2, 5, 8, 9, 1] print(len(list1)) print(max(list1)) print(min(list1)) コンソール出⼒ /chapter3/len_max_min.py $ python3 len_max_min.py 6 9 1
  124. filter関数でリストの要素を絞り込む • リストから特定条件を満たす要素を取り出す処理は多⽤する • 「filter関数」にリストと条件判定の関数を与えて実現可能 • 返り値はループで直接使えるが、リスト型ではないので注意が 必要。リストが必要な場合は「list関数」でキャストする $ python3

    filter.py [4, 2, 8] def is_even(x): return x % 2 == 0 list1 = [4, 2, 5, 8, 9, 1] filter_object = filter(is_even, list1) list2 = list(filter_object) print(list2) コンソール出⼒ /chapter3/filter.py リスト型へのキャスト
  125. map関数でリストをまとめて処理する • リストの要素全てに特定の処理を施す場⾯は多い • 「map関数」にリストと関数を与えると、リストの全要素に関 数の処理を実施した結果を返す def add5(x): return x

    + 5 list1 = [4, 2, 5, 8, 9, 1] map_object = map(add5, list1) for i in map_object: print(i) $ python3 map.py 9 7 10 13 14 6 コンソール出⼒ /chapter3/map.py
  126. • range関数とforループを使って指定された数だけ「hello」と出 ⼒する関数を作成してください • 正と負の整数を持つリストをfilter関数と⾃作関数を使って正の 整数のみを抽出したリストにしてください。たとえば[5, -3, 8, -1, 4]を与えると[5,

    8, 4]が得られます • map関数を使って数値を含むリストを⽂字列を含むリストに変 換してください。たとえば[5, -3, 8, -1, 4]を与えると['5', '-3', '8', '-1', '4']が得られます 演習
  127. オブジェクト指向を理解しよう CHAPTER 4 1. オブジェクトとメソッドの関係を理解する 2. リストオブジェクトを操作する 3. 不変オブジェクトを操作する 4.

    その他のデータ型を理解する
  128. オブジェクトとメソッドの関係を理解する • このセクションで学ぶこと • オブジェクトとは • メソッドでListインスタンスを操作する • メソッドの副作⽤と返り値 •

    コラム: dir関数を使ったオブジェクトのメソッド確認 SECTION 01
  129. オブジェクトとは • ⽂字列型や整数型には概念と実データが存在する • 型の概念のことを「クラス」と呼ぶ • 型の実データ(値)を「インスタンス」や「オブジェクト」と呼ぶ

  130. メソッドでListインスタンスを操作する (1/2) • 「メソッド」はインスタンスを操作するための特別な関数 • インスタンス(値そのものか変数)の後ろに「.(ドット)」を置き、 続けてメソッド名とメソッドの引数を記述する • appendメソッド: 対象のインスタンスに要素を追加

    • reverseメソッド: 対象のインスタンスの要素の順序を反転 a = ['ab', 'cd', 'ef'] print(a) # リストに値を追加 a.append('gh') print(a) $ python3 object_02.py ['ab', 'cd', 'ef'] ['ab', 'cd', 'ef', 'gh'] a = ['ab', 'cd', 'ef', 'gh'] a.reverse() # リストの要素を反転 print(a) $ python3 object_03.py ['gh', 'ef', 'cd', 'ab'] コンソール出⼒ コンソール出⼒ /chapter4/object_02.py /chapter4/object_03.py
  131. メソッドでListインスタンスを操作する (2/2) • メソッドの操作対象はインスタンス内のデータ • インスタンス内ではデータと処理が密接に結びついている • 利⽤できるメソッドはインスタンスの型に依存する。たとえばList 型インスタンスと⽂字列型インスタンスが使えるメソッドは違う

  132. メソッドの副作⽤と返り値 • 「副作⽤」は操作によりオブジェクトの状態が変化すること • メソッドには以下のパターンが存在する • 副作⽤はあるが、返り値はない(Listのappendメソッド) • 副作⽤はなく、返り値がある(Listのcountメソッド) •

    副作⽤も返り値もある(Listのpopメソッド) • 副作⽤も返り値もない(呼び出す意味がないので普通はない) a = [1,3,5,3,1,3] b = a.count(3) print(b) print(a) $ python3 object_05.py 3 [1, 3, 5, 3, 1, 3] a = [1,3,5,3,1,3] b = a.pop(0) print(b) print(a) $ python3 object_06.py 1 [3, 5, 3, 1, 3] コンソール出⼒ コンソール出⼒ /chapter4/object_05.py /chapter4/object_06.py 副作⽤なし 返り値あり 副作⽤あり 返り値あり
  133. コラム: dir関数を使ったオブジェクトのメソッド確認 • どの型がどういったインスタンスを使えるか記憶しきれない • dir関数を使うことでオブジェクトの属性(5章)を確認できる • メソッドも属性の⼀部なので確認可能 >>> dir([])

    ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] コンソールで属性(メソッド)の⼀覧を確認
  134. • リストの「[1,2,3,4]」はクラスですか、インスタンスですか • 「クラス」と「インスタンス」の関係について説明してくださ い • インスタンスのメソッドがなにかについて説明してください • 以下のリストのメソッドの副作⽤と返り値を説明してください •

    append • reverse • count • pop 演習
  135. リストオブジェクトを操作する • このセクションで学ぶこと • リストオブジェクトを操作するメソッド • その他のリスト操作 SECTION 02

  136. リストオブジェクトを操作するメソッド (1/4) • append: リスト末尾に要素を追加する • insert: 指定した位置に要素を挿⼊する a =

    ['a', 'b', 'c', 'd', 'e'] a.append('hello') print(a) a = ['a', 'b', 'c', 'd', 'e'] a.insert(3, 'hello') print(a) $ python3 list_method_01.py ['a', 'b', 'c', 'd', 'e', 'hello'] $ python3 list_method_02.py ['a', 'b', 'c', 'hello', 'd', 'e'] コンソール出⼒ コンソール出⼒ /chapter4/list_method_01.py /chapter4/list_method_01.py
  137. リストオブジェクトを操作するメソッド (2/4) • remove: 指定した要素を削除する。インデックス指定ではなく 消したい値を指定するので注意 • reverse: リストの順序を反転させる a

    = ['a', 'b', 'c', 'd', 'e'] a.remove('c') print(a) $ python3 list_method_03.py ['a', 'b', 'd', 'e'] a = ['a', 'b', 'c', 'd', 'e'] a.reverse() print(a) $ python3 list_method_04.py ['e', 'd', 'c', 'b', 'a'] コンソール出⼒ コンソール出⼒ /chapter4/list_method_03.py /chapter4/list_method_04.py
  138. リストオブジェクトを操作するメソッド (3/4) • clear: リストの要素を全削除して空にする • count: リストに指定した要素がいくつあるか数える a =

    ['a', 'b', 'c', 'd', 'e'] a.clear() print(a) a = ['a', 'b', 'c', 'b', 'a'] count = a.count('b') print(count) $ python3 list_method_06.py 2 $ python3 list_method_05.py [] コンソール出⼒ コンソール出⼒ /chapter4/list_method_05.py /chapter4/list_method_06.py
  139. リストオブジェクトを操作するメソッド (4/4) • index: 指定した値を持つ要素のインデックス番号を取得 • pop: リストからインデックスを指定して要素を取り出して削除 a =

    ['a', 'b', 'c', 'd', 'e'] index = a.index('d') print(index) a = ['a', 'b', 'c', 'd', 'e'] value = a.pop(0) print(value) print(a) $ python3 list_method_07.py 3 $ python3 list_method_08.py a ['b', 'c', 'd', 'e'] コンソール出⼒ コンソール出⼒ /chapter4/list_method_07.py /chapter4/list_method_08.py
  140. その他のリスト操作 (1/2) • 「in演算⼦」で指定した値がリストに含まれていればTrueを返す • 「del⽂」で指定したインデックス番号の要素を削除 a = 'c' in

    ['a', 'b', 'c', 'd'] print(a) print('c' in ['a', 'b', 'd']) a = ['a', 'b', 'c', 'd', 'e'] del a[3] print(a) $ python3 list_operator01.py True False $ python3 list_operator02.py ['a', 'b', 'c', 'e'] コンソール出⼒ コンソール出⼒ /chapter4/list_operator_01.py /chapter4/list_operator_02.py
  141. その他のリスト操作 (2/2) • 「スライス」でリストの要素の⼀部分を取り出せる。元のリストに は変化なし • a[x:y] : リストaのインデックス番号xからy-1の要素のリストを取得 •

    a[:y] : インデックス番号0からy-1までの要素のリストを取得 • a[x:] : インデックス番号のxから最後までの要素のリストを取得 • a[:] : リストaをコピーしたリストを取得 a = ['a', 'b', 'c', 'd', 'e'] b = a[1:3] print(b) c = a[:3] print(c) $ python3 list_operator03.py ['b', 'c'] ['a', 'b', 'c'] コンソール出⼒ /chapter4/list_operator_03.py
  142. • 「[1,2,3,4,5]」を持つリストをinsertで「[1,2,3,100,4,5]」にし てください • 整数を含むリストから偶数だけを抽出したリストを作成してく ださい。ただしfilter関数などは使わず「forループ内で事前に作 成した偶数リストに偶数を追加」という⽅式です。 • 「[1,2,3,4,5]」というリストをwhileとpopを使って 5,

    4, 3, 2, 1 と逆順序に要素がなくなるまで取り出してください。reverseメ ソッドの利⽤は禁⽌です。ヒント: FIFOとスタックというデー タ構造を調べてください 演習
  143. 不変オブジェクトを操作する • このセクションで学ぶこと • ⽂字列型のメソッドはオブジェクトを変化させない • ⽂字列型のメソッド • in演算⼦を使った⽂字列型の処理 •

    ⽂字列の⼀部を取り出す • コラム: メソッドチェーン SECTION 03
  144. ⽂字列型のメソッドはオブジェクトを変化させない (1/2) • upper: ⽂字列を⼤⽂字にした「新しい⽂字列を返す」 • replace: ⽂字列を置き換えた「新しい⽂字列を返す」 • 上記2つのメソッドを呼び出してもインスタンスは変化しない

    a = 'Hello Python' b = a.upper() print('Original a : ' + a) print('Return val b : ' + b) a = 'Hello Python' c = a.replace('Hello', 'Hell') print('Original a : ' + a) print('Return val c : ' + c) $ python3 string_method_01.py Original a : Hello Python Return val b : HELLO PYTHON $ python3 string_method_02.py Original a : Hello Python Return val c : Hell Python コンソール出⼒ コンソール出⼒ /chapter4/string_method_01.py /chapter4/string_method_01.py
  145. ⽂字列型のメソッドはオブジェクトを変化させない (2/2) • 「不変オブジェクト」は⾃分⾃⾝を変化させないオブジェクト • ほとんどの型は不変オブジェクトではないが、原始的な型(整数 型や⽂字列型)は不変オブジェクトであることが多い

  146. ⽂字列型のメソッド (1/5) • formatメソッド: ⽂字列に値を埋め込む。+演算⼦で⽂字列化し て連結するよりも綺麗に書ける • ⽂字列中の{}に引数が埋め込まれた⽂字列を返す • 埋め込む値の整形やキーワードでの埋め込みもできる(割愛)

    name = 'Tom' age = 25 text = 'Hi, this is {}. {} years old.'.format(name, age) print(text) $ python3 string_method_03.py Hi, this is Tom. 25 years old. コンソール出⼒ /chapter4/string_method_03.py
  147. ⽂字列型のメソッド (2/5) • startswithメソッド: 引数の⽂字列で開始されていればTrue • endswithメソッド: 引数の⽂字列で終了していればTrue print('Hello Python'.startswith('thon'))

    print('Hello Python'.startswith('Hello')) print('Hello Python'.endswith('thon')) print('Hello Python'.endswith('Hello')) $ python3 string_method_04.py False True $ python3 string_method_05.py True False コンソール出⼒ コンソール出⼒ /chapter4/string_method_04.py /chapter4/string_method_05.py
  148. ⽂字列型のメソッド (3/5) • replaceメソッド: 第1引数の⽂字列を第2引数の⽂字列で置き 換えた⽂字列を返す • lowerメソッド: ⽂字列を全て⼩⽂字にした⽂字列を返す •

    upperメソッド: ⽂字列を全て⼤⽂字にした⽂字列を返す print('Hello Python'.replace('Python', 'World')) print('Hello Python'.replace('Pyth0n', 'World')) print('Hello Python'.replace('Python', '')) $ python3 string_method_06.py Hello World Hello Python Hello >>> a = 'Hello World' >>> a.lower() 'hello world' >>> a.upper() 'HELLO WORLD' >>> a.lower() == 'hello world' True lowerもしくはupperで⼤⽂字⼩⽂字を 気にせずに⽂字列の合致判定ができる コンソール出⼒ lowerとupperメソッドの確認 /chapter4/string_method_06.py
  149. ⽂字列型のメソッド (4/5) • stripメソッド: ⽂字列の前後の空⽩(半⾓空⽩、改⾏、タブな ど)を取り除く • joinメソッド: リストの要素を⽂字列で連結する print('

    hello\n') print(' hello\n'.strip()) list3 = ['taro', '180', '80'] text = ','.join(list3) print(text) $ python3 string_method_07.py hello hello $ python3 string_method_10.py taro,180,80 コンソール出⼒ コンソール出⼒ /chapter4/string_method_07.py /chapter4/string_method_08.py
  150. ⽂字列型のメソッド (5/5) • splitメソッド: ⽂字列を特定の⽂字列で分解して⽂字列のリス トにする • CSV形式をコンマで分けたり、改⾏コードで複数⾏のテキスト を⾏ごとに分解する処理によく使われる text

    = 'taro, 180, 80' list1 = text.split(',') print(list1) text = 'taro, 180, 80' list1 = text.split(',') def apply_strip(text): return text.strip() list2 = list(map(apply_strip, list1)) print(list2) $ python3 string_method_08.py ['taro', ' 180', ' 80'] $ python3 string_method_09.py ['taro', '180', '80'] コンソール出⼒ コンソール出⼒ /chapter4/string_method_08.py /chapter4/string_method_09.py
  151. in 演算⼦を使った⽂字列型の処理 • 特定の⽂字列が別の⽂字列内に含まれるかをin演算⼦で判別で きる。返り値はTrue/False • 複雑な条件で⽂字列判定がしたい場合は8章の正規表現を使う print('Hell' in 'Hello')

    print('Ho' in 'Hello') $ python3 string_operator_01.py True False コンソール出⼒ /chapter4/string_operator_01.py
  152. ⽂字列の⼀部を取り出す • ⽂字列はシーケンス型(リストなど)の1つ • []でインデックスを指定して特定位置の1⽂字を抜き出せる • []を使ったスライスで⽂字列の特定箇所を抜き出せる • ⽂字列のスライスの利⽤法は4章2節のリストのスライスと同じ $

    python3 string_operator_02.py l lo py text = 'hello python' print(text[3]) print(text[3:8]) コンソール出⼒ /chapter4/string_operator_02.py
  153. コラム: メソッドチェーン • 返り値を変数に格納せずに直接メソッドを呼び出せる • 鎖状に連ねることから「メソッドチェーン」と呼ばれる

  154. • 不変オブジェクトについて例を使って説明してください • ⽂字列型のformatメソッドでテンプレートを埋めてください。 「'hello {}'」 • ⽂字列型のlowerを使って⽂字列からbool値を得る関数を作成 してください •

    引数が⼤⽂字⼩⽂字を問わず「true」であればTrue • それ以外は全てFalse • replaceメソッドで⽂字列「"Hello I'm Yuichi"」の名前を⾃分の 名前に変えてください。 • メソッドチェーンで「'hello world python'」を1⾏で 「['HELLO', 'WORLD', 'PYTHON']」にしてください 演習
  155. その他のデータ型を理解する • このセクションで学ぶこと • タプルの概要 • タプルの利⽤⽅法と利⽤例 • タプルからタプルへの代⼊(アンパック代⼊) •

    タプルやリストを扱う関数 • セットの概要 • セット型の操作 • 辞書型の概要 • 辞書型の操作 • 辞書型のメソッド • コラム: 基本的な型と制御がプログラミングの中⼼ SECTION 04
  156. タプルの概要 • 複数の異なるデータをまとめて管理するための型。リストに似 ているが「不変オブジェクト」。データ構造を作る • 出席簿を例としたリストとの使い分け • タプル: 各⽣徒のデータ(名前、⾝⻑、体重) •

    リスト: ⽣徒1, ⽣徒2, ⽣徒3, ...
  157. タプルの利⽤⽅法 • 少カッコ()内に各要素をコンマ区切りで並べる。リストと同じ • 要素へのアクセスはインデックス番号を使う • 要素は上書きできない • 要素数は変更できない taro

    = ('taro', 180, 80) print(type(taro)) print(taro[1]) $ python3 tuple_02.py <class 'tuple'> 180 >>> taro = ('taro', 180, 80) >>> taro[0] = 'jiro' Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'tuple' object does not support item assignment >>> del taro[1] Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'tuple' object doesn't support item deletion インタプリタでの挙動確認 /chapter4/tuple_02.py コンソール出⼒
  158. タプルの利⽤例 • 表の列(構成が決まっている)をタプルとする • 表の⾏(⻑さが変わる)をリストとする taro = ('taro', 180, 80)

    jiro = ('jiro', 170, 70) saburo = ('saburo', 160, 60) list1 = [taro, jiro, saburo] sum_height = 0 for person in list1: sum_height += person[1] print(sum_height/len(list1)) $ python3 tuple_03.py 170.0 /chapter4/tuple_03.py コンソール出⼒
  159. タプルからタプルへの代⼊ • 「アンパック代⼊」を使うとタプルに含まれる変数群に右側の タプルの要素をまとめて代⼊できる • 左辺のカッコは省略できる。例「a, b, c = (1,

    2, 3)」 • for⽂の変数や関数の返り値にタプルを使うことが多い (name, height, weight) = ('taro', 180, 80) print(height) taro = ('taro', 180, 80) jiro = ('jiro', 170, 70) saburo = ('saburo', 160, 60) list1 = [taro, jiro, saburo] sum_height = 0 for (name, height, weight) in list1: sum_height += height print(sum_height/len(list1)) $ python3 tuple_04.py 180 $ python3 tuple_05.py 170.0 /chapter4/tuple_04.py /chapter4/tuple_05.py コンソール出⼒ コンソール出⼒
  160. タプルやリストを扱う関数 • 「enumerate関数」でリストの要素をタプル形式にしてイン デックス番号を与える • 「zip関数」で複数のリストを束ねてタプル形式のリストにする list1 = ['a', 'b',

    'c', 'd', 'e'] enum_object = enumerate(list1) print(list(enum_object)) list1 = ['a', 'b', 'c'] for (index, item) in enumerate(list1): print('{} : {}'.format(index, item)) $ python3 tuple_06.py [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd'), (4, 'e')] $ python3 tuple_07.py 0 : a 1 : b 2 : c /chapter4/tuple_06.py /chapter4/tuple_07.py コンソール出⼒ コンソール出⼒ enumerateはforループでインデックス値が必要な時に便利
  161. セットの概要 • 順序と重複がない複数の要素を保持するデータ構造 • 要素を追加、削除することができるが、Listと異なり同じ要素 を2つ持つことはできず、要素の順序もない • set()で空のセットオブジェクトを作成する >>> set1

    = set() >>> set1.add('apple') >>> print(set1) {'apple’} >>> set1.add('banana') >>> print(set1) {'banana', 'apple’} >>> set1.add('apple') >>> print(set1) {'banana', 'apple'} インタプリタでの挙動確認(詳細は次ページより)
  162. セット型の操作 (1/2) • セットオブジェクトの作成⽅法 • set() • {'elem1', 'elem2', 'elem3'}

    • 宣⾔⽅法が後述する辞書型とほぼ同じなので注意。特に「{}」 はセット型ではなく辞書型のオブジェクトが⽣成されるのはよ く間違えるポイント >>> set1 = set() >>> type(set1) <class 'set'> >>> set2 = {'elem1', 'elem2', 'elem3'} >>> type(set2) <class 'set'> インタプリタでの挙動確認
  163. セット型の操作 (2/2) • addメソッド: 要素を追加 • removeメソッド: 要素を削除 • popメソッド:

    要素をランダムに取り出し(取り出すとなくなる) • in演算⼦: 要素が存在するかチェック。リストより⾼速 >>> set1 = {'A', 'B', 'C'} >>> 'A' in set1 True >>> 'D' in set1 False >>> set1.remove('B') >>> set1 {'C', 'A’} >>> a = set1.pop() >>> a 'C’ >>> set1 {'A'} インタプリタでの挙動確認
  164. 辞書型の概要 • セットと似ているが要素は「キー(key)」と「バリュー (value)」を持つ。キーは重複できないがバリューは重複できる • キーを指定してバリューを取得/更新する • 同じキーで要素を追加するとバリューが上書きされる >>> fruits_dict

    = dict() >>> fruits_dict['apple'] = 'red' >>> fruits_dict['banana'] = 'yellow' >>> fruits_dict {'apple': 'red', 'banana': 'yellow'} >>> fruits_dict['apple'] 'red' インタプリタでの挙動確認(詳細は次ページより)
  165. 辞書型の操作 (1/3) • 辞書オブジェクトの作成⽅法 • dict() • {} • {key1:value1,

    key2:value2, ...} • セット型と使う記号が同じ中括弧。違いは要素がキーとバ リューのペアになっていることのみ • キーの型は⽂字列が⼀般的だが他の型(数値など)も使える >>> fruits_dict = {'apple':'red', 'banana':'yellow'} >>> type(fruits_dict) <class 'dict’> >>> fruits_dict2 = {} >>> type(fruits_dict) <class 'dict'> インタプリタでの挙動確認
  166. 辞書型の操作 (2/3) • 辞書オブジェクトからのバリューの取得 • 書式: OBJECT[KEY] • 辞書オブジェクトへの要素の追加 •

    存在しないキー: 新しいキーとバリューのペアが登録される • 存在するキー: キーの対となるバリューが更新される • 書式: OBJECT[KEY] = VALUE >>> fruits_dict = {'apple':'red', 'banana':'yellow'} >>> fruits_dict['apple'] 'red' >>> fruits_dict['apple'] = 'green' >>> fruits_dict['apple'] 'green' インタプリタでの挙動確認
  167. 辞書型の操作 (3/3) • in演算⼦: キーの存在確認 • 存在しないキーのバリューを取得しようとするとエラーになる • キーの存在が不明な場合は事前にin演算⼦か後述のgetメソッド を使うこと

    >>> fruits_dict = {'apple':'red', 'banana':'yellow'} >>> 'apple' in fruits_dict True >>> 'grape' in fruits_dict False >>> fruits_dict['grape'] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'grape' インタプリタでの挙動確認
  168. 辞書型のメソッド (1/4) • keys: キーの⼀覧をリスト形式で返す • values: バリューの⼀覧をリスト形式で返す • items:

    「キーとバリューのタプル」をリスト形式で返す • itemsはforループでの利⽤に便利 >>> a = {'apple':'red', 'banana':'yellow'} >>> a.keys() dict_keys(['apple', 'banana']) >>> a.values() dict_values(['red', 'yellow']) >>> a.items() dict_items([('apple', 'red'), ('banana', 'yellow')]) インタプリタでの挙動確認
  169. 辞書型のメソッド (2/4) • 辞書型をforループで全て処理する操作 • for⽂のin演算⼦に辞書オブジェクトを与える: keyでループ • for⽂のin演算⼦にitemsメソッドを与える: keyとvalueでループ

    fruits_dict = {'apple':'red', 'banana':'yellow'} for key in fruits_dict: print(key) fruits_dict = {'apple':'red', 'banana':'yellow'} for (key, value) in fruits_dict.items(): print('{} : {}'.format(key, value)) $ python3 dict_01.py apple banana $ python3 dict_02.py apple : red banana : yellow /chapter4/dict_01.py /chapter4/dict_02.py コンソール出⼒ コンソール出⼒
  170. 辞書型のメソッド (3/4) • get: キーを指定してバリューを取得する。キーが存在しない場 合はデフォルト値を取得 • デフォルト値を指定しない場合はNoneがデフォルト値 • デフォルト値を取得しても元の辞書オブジェクトに変化なし

    • 似た関数にsetdefaultがある(割愛) page_counter = {} value = page_counter.get('/hello.html', 0) print(value) print(page_counter) $ python3 dict_03.py 0 {} /chapter4/dict_03.py コンソール出⼒
  171. 辞書型のメソッド (4/4) • getメソッドを使うことでカウンターのような実装を簡単に実 現できる • 複雑な初期化処理が必要な場合はin演算⼦を使って以下のよう な実装をすることを推奨 • 存在しない場合:

    初期化処理をして辞書オブジェクトに代⼊ • 存在する場合: 辞書オブジェクトから取得 page_counter = {} page_counter['/page_a.html'] = page_counter.get('/page_a.html', 0) + 1 page_counter['/page_a.html'] = page_counter.get('/page_a.html', 0) + 1 page_counter['/page_b.html'] = page_counter.get('/page_b.html', 0) + 1 print(page_counter) $ python3 dict_04.py {'/page_a.html': 2, '/page_b.html': 1} /chapter4/dict_04.py コンソール出⼒
  172. コラム: 基本的な型と制御がプログラミングの中⼼ • Pythonプログラミングの基本は以下となる • ライブラリにある処理はライブラリに任せる • ライブラリを使うプログラムは⾃分で作る(貼り合わせ) • 後者はこの章までに学んだ基本的な型(数値、⽂字列、リスト、

    タプル、セット、辞書型)を基本的な制御(if, for, while)で操作 するのが上級者でもおよそコードの8割以上と思われる • すでに学んだ関数や今後学ぶクラスや例外処理などは上記の ベーシックなプログラムを整理するためのもの。⾼度なプログ ラミングテクニックを学ぶ前に基礎を抑えるのが⼤事 • フルスクラッチで素材から開発するのではなく、ライブラリと いう「レゴの出来合いのパーツ」をスマートに⾃分のコードで 張り合わせて作品を作るのがPython流のプログラミング
  173. コラム: 著者の型の使い分け • タプル: 引数や返り値で値をまとめる • リスト: 可変⻑の複数の要素を管理するために使う。なにかを ループ処理するときに使う第⼀候補。要素探索が遅いので注意 •

    セット: 要素の存在チェックが必要な場合にリスト代替で使う • 辞書型: リストに似た使い⽅だが、要素をすばやく検索できる 必要がある場合に使う。辞書型のキーは「データベースでいう 主キーやインデックス」で、それを使って該当エントリを素早 く抜き出すようなイメージ。Pythonプログラミングでは辞書型 が⾮常に便利なので使いこなそう。 • 余談: 辞書型とListの特徴をあわせ持つ 「順序付き辞書 (OrderedDict)」などの変種もある
  174. • 数値のリストを受け取り、そこから最⼩値と最⼤値を同時に返 す関数 get_min_max を作成し、その関数の返り値の最⼩値と 最⼤値をそれぞれ別の⾏でコンソールに出⼒してください。 • リスト型での要素の探索に⽐べて、セット型での要素の探索が ⾼速である理由をインターネットで調べてください。 •

    数値のリストを受け取り、各数値が何回出現したかをカウント する関数を辞書型を使って作成してください。返り値は{数値1: 出現数1, 数値2:出現数2, ...}という形式とします。 • 上記関数の出⼒をforループでキーとバリューのペアごとに 「'{} : {}'.format(key, value)」というフォーマットでプリント 出⼒してください。 演習
  175. クラスの使い⽅をマスターしよう CHAPTER 5 1. クラスの仕組みと設計⽅法を知る 2. クラスの必要性を理解する 3. クラスの⾼度な使い⽅を知る

  176. クラスの仕組みと設計⽅法を知る • このセクションで学ぶこと • クラスとは • この章の学習の流れ • クラスとメソッドを定義する •

    ⾃分で定義したクラスのインスタンスを作成 • メソッド定義の第⼀引数selfは⾃動で代⼊される • クラスの命名規則 • インスタンス変数 • コンストラクタでのインスタンス変数の定義 • メソッド間のインスタンス変数の共有 • インスタンス変数の外部からの参照 SECTION 01
  177. クラスとは • 複雑なデータと処理をまとめるための⽂法 • クラスを使わないとプログラムが⼤規模化した際に「どの関数 がどのデータを使うか」を管理しにくくなる • クラスで枠を作ることで構造をプログラマに強制する

  178. この章の学習の流れ • クラスの概念の理解は難所のため、以下の順を追って学ぶ 1. Section1 : クラスとメソッドの定義⽅法 2. Section1 :

    クラスをインスタンス化する⽅法 3. Section1 : データ(インスタンス変数)の定義 4. Section2 : クラスの有無によるプログラムの⽐較 5. Section3 : その他のトピック
  179. クラスとメソッドを定義する • classに続けてクラス名を書く • classのブロック内にメソッドを関数と同じくdefで定義 • メソッドの第⼀引数は常に「self」とする class MyClass: def

    plus(self, a, b): return a + b def minus(self, a, b): return a - b /chapter5/myclass.py クラスの定義 インスタンスが使うメソッドの定義
  180. ⾃分で定義したクラスのインスタンスを作成 • 「クラス名()」でインスタンス化をおこなう • インスタンス.メソッド名()でメソッドの呼び出しを⾏なう • 呼び出し側で引数selfに相当するものを与えていない(後述) class MyClass: def

    plus(self, a, b): return a + b def minus(self, a, b): return a - b myclass = MyClass() a = myclass.plus(5, 3) print(a) b = myclass.minus(5, 3) print(b) $ python3 myclass.py 8 2 /chapter5/myclass.py コンソール出⼒
  181. メソッド定義の第⼀引数selfは⾃動で代⼊される • 引数の数の違い • クラスでの定義: 3つ。 下図のminusは「self, a, b」 •

    メソッドで与える数: 2つ。数のminusは「7, 5」 • Pythonのクラスでのメソッド定義のルール • 第⼀引数はselfとする • selfにはインスタンス⾃⾝が代⼊されている(利⽤法は後述)
  182. クラスの命名規則 • 単語の区切りを⼤⽂字にする • クラス名の例 • MyClass • User •

    BingoMachine • この命名ルールは⼀般的に「キャメルケース」と呼ばれる。 キャメルはラクダで、⼤⽂字⼩⽂字の連なりがラクダのコブの ようにぼこぼこしているため
  183. インスタンス変数 • 「インスタンス変数」は同⼀インスタンスのメソッド間で共有 される変数 • インスタンス変数はインスタンスごとに独⽴している • 同⼀クラスから作られた複数インスタンスの差はインスタンス 変数のみ。メソッドの処理などに違いはない クラスでインスタンス変数を定義

    - name - age インスタンスでインスタンス変数に 具体的な値が代⼊される - name = beckey - age = 40
  184. コンストラクタでのインスタンス変数の定義 • Pythonでインスタンス変数を定義するのは「コンストラクタ」 • コンストラクタは特殊なメソッドで「__init__(self, 初期化のた めの引数)」とし、処理でインスタンス変数の初期化を書く • 「self.インスタンス変数名 =

    初期価値」として変数定義 • コンストラクタはクラスのインスタンス化時に呼び出される class User: def __init__(self, x, y): self.name = x self.age = y def dump(self): print('name:{}'.format(self.name)) print('age:{}'.format(self.age)) ana = User('ana', 30) ana.dump() $ python3 define_instance.py name:ana age:30 /chapter5/define_instance.py コンソール出⼒
  185. メソッド間のインスタンス変数の共有 • メソッドの第⼀引数 selfはオブジェクト⾃⾝ • コンストラクタ内で⾃分⾃⾝にインスタンス変数を追加(定義) • メソッド内で⾃分⾃⾝が持つ変数にアクセス(read/write) self: インスタンス⾃⾝

    name age コンストラクタ __init__ メソッド dump 初期化 (作成) 参照
  186. インスタンス変数の外部からの参照 • インスタンス変数はメソッド内部だけでなく「インスタンス.イ ンスタンス変数名」としても参照できる • この利⽤法はJavaなどでは⾮推奨とされるがPythonは問題ない ので不必要なセッターやゲッターは作らないこと class User: def

    __init__(self, x, y): self.name = x self.age = y def dump(self): print('name:{}'.format(self.name)) print('age:{}'.format(self.age)) ana = User('ana', 30) print(ana.name) print(ana.age) $ python3 check_instance.py ana 30 /chapter5/check_instance.py コンソール出⼒
  187. • 以下のクラスを作成してください • クラス名: User • 以下のインスタンス変数を持ち、コンストラクタで初期化 • id •

    name • address • 以下のメソッドを持つ • dumps: ⽂字列のformatメソッドを使ってCSV形式で「id, name, address」を⽂字列で返す • 上記クラスをインスタンス化してdumpsの結果を出⼒する 演習
  188. クラスの必要性を理解する • このセクションで学ぶこと • ⽐較題材のプログラムについて • クラスを使わないプログラムの実装 • 中級者向け: 関数内での参照と代⼊の違い

    • クラスを使わないプログラムの実⾏ • クラスを使うプログラムの実装 • なぜクラスが必要か • インスタンスに閉じた副作⽤を使う • 正しいクラスの設計ができたら中級者 SECTION 02
  189. ⽐較題材のプログラムについて • クラスを使うべき理由を具体例(ビンゴマシーン)で確認する • 仕組み • 1-99の番号が振られたボールをランダムに抽出する • 同じボールは⼀度しか出ない •

    全てのボールがなくなったら終了 ボール群をリストとする リストに要素(ボール)を追加 リストの要素(ボール)の順序を シャッフルして1つ取り出す 同じ仕組みをクラスなし/ありで実装
  190. クラスを使わないプログラムの実装 • ビンゴを実現する関数 • initialize: 1-99のボール揃える • get_ball: ランダムにボールを取り出す(ランダム操作は6章) •

    has_ball: まだボールがあるか確認 • プログラムの問題: 引数経由でしかデータ共有ができない import random # ランダムな機能を使うという宣⾔ def initialize(balls1): balls1.clear() # リストを空にする balls1.extend(list(range(1, 100))) # リストに1-99を⼊れる def get_ball(balls1): random.shuffle(balls1) # リストをランダムに並べ替える return balls1.pop() def has_ball(balls1): return len(balls1) != 0 balls2 = [] initialize(balls2) # ボールがあればビンゴを回す while has_ball(balls2): print(get_ball(balls2)) 続き /chapter5/bingo_01.py
  191. 中級者向け: 関数内での参照と代⼊の違い • さきほどのinitializeで引数balls1にリストを代⼊すると失敗する • 引数をextendメソッドで参照して要素変更すると成功 • 深いレベルの知識(ポインタの概念)を理解していないと間違える 第3章で関数外の変数を 関数内で更新する例と

    実はほとんど同じ動き bingo_01.py bingo_02.py
  192. クラスを使わないプログラムの実⾏ • /chapter5/bingo_01.py: 2ページ前の正しいプログラム • /chapter5/bingo_02.py: 参照ではなく代⼊する誤ったプログラム $ python3 bingo_01.py

    29 41 93 28 84 ... 32 22 5 49 83 80 13 $ python3 bingo_02.py ボールの初期化に成功している。 そのあとのランダムな取り出し処理も ボールがなくなるまで繰り返す。 ボールの初期化に失敗してリストが空のまま。 取り出すボールがないので取り出し処理はおきない bingo_01.pyの実⾏結果 bingo_02.pyの実⾏結果
  193. クラスを使うプログラムの実装 (1/2) • クラスを使うことでメソッド間でデータ(ビンゴのボール)をイ ンスタンス変数として共有できる • あるメソッドでの変更(たとえば初期化や取り出し)が、別のメ ソッドでも反映される import random

    class Bingo: def __init__(self): self.balls = list(range(1, 100)) def get_ball(self): random.shuffle(self.balls) return self.balls.pop() def has_ball(self): return len(self.balls) != 0 bingo = Bingo() while bingo.has_ball(): print(bingo.get_ball()) 続き /chapter5/bingo_03.py
  194. クラスを使うプログラムの実装 (2/2) • 初⼼者にはクラスという⽂法で難しく⾒えるかもしれない • 処理(メソッド)間で「データ(インスタンス変数)を共有するこ と」が簡単になる • 難しい参照と代⼊の違いを意識しないでも動く

  195. なぜクラスが必要か ⽐較項⽬ クラスなし クラスあり ⽂法 シンプル 複雑 変数と関数 同じ空間上に多数存在 クラス内の数は少ない

    データの共有 難しい メソッド間はインスタンス変数を使えば簡単 データ構造の定義 タプルやリストなどの組み合わせ クラスで構造を定義し、新しい型を作れる 初期化処理 ⾃分で任意で実⾏ コンストラクタで⾃動で実施 副作⽤の利⽤ 管理しにくいので避けるべき クラス内では積極的に使うべき デバッグ しにくい 整理されているためやりやすい 総合判断 単純なプログラム向け 複雑なプログラムでは必須 • 複雑なプログラムを構造化することで、データや制御の流れをシ ンプルにできるため。難しさをクラス内に押し込める • 逆に⾔えばシンプルなプログラムではクラスを使わなくてもよい 気になる⼈は「カプセル化」というキーワードで調べてみるとよいかも
  196. インスタンスに閉じた副作⽤を使う • ⼀般的にプログラミングでは副作⽤(3章)を減らすのが望ましい • ただしインスタンス内の変数にたいしては例外 • プログラムの影響範囲がクラス定義内と限定的 • 外部の複雑さをクラス内に押し込むことで全体を綺麗にする •

    インスタンスを使う側が簡単に使えることを最も優先する
  197. 正しいクラスの設計ができたら中級者 • オブジェクト指向のクラスの⽂法は頑張れば覚えられる • 正しいオブジェクト指向の設計は勉強だけでなく経験が必要 • 上級者でも設計変更は発⽣するので完璧なものを最初から作ろ うとするのではなく、作って修正を繰り返して慣れるのがよい ブラック ボックス

    複雑な プログラム 複雑な プログラム 利⽤する側の プログラム クラス内部の複雑なプログラムを 意識せず表⾯的に他のクラスを使う 分かりやすい メソッドの定義
  198. • テキストを追加するクラスを作成してください • インスタンス変数 self.text = “”をコンストラクタで定義 • メソッドadd_text: インスタンス変数self.textに引数のテキスト

    を追加 演習 ta = TextAdder() ta.text '' ta.add_text('hello') ta.text 'hello' ta.add_text(' world') ta.text 'hello world' 操作イメージ
  199. • ⽂字の出現数(空⽩を含む)をカウントするクラスを作成してく ださい • コンストラクタ: 引数はselfのみでインスタンス変数 self.char_counterに{}を設定する • メソッド •

    add_text: 引数はselfとtext(⽂字列)で、メソッド内でtextを1 ⽂字ごとforループで回す。出現する⽂字を self.char_counterで数える(ヒント: dictのgetメソッドと初期 値を使うと実装が簡単) • get_counts: インスタンス変数 self.char_counter の値を返 す。 演習
  200. クラスの⾼度な使い⽅を知る • このセクションで学ぶこと • クラス変数 • クラスメソッド • クラスの継承 •

    コラム: 初⼼者はあまり継承を使わない? SECTION 03
  201. クラス変数 • 「クラス変数(定数)」はインスタンスをまたいで共有されるクラス レベルの変数(定数)で、クラス直下に定義する • クラス内で「クラス名.クラス変数名」で参照や代⼊をおこなう class MyClass: abc =

    'abc' DEF_GHI ='def ghi' def print_abc(self): print(MyClass.abc) def set_abc(self, abc): MyClass.abc = abc a = MyClass() b = MyClass() # クラス変数の変更前 a.print_abc() b.print_abc() # クラス変数の変更後 a.set_abc('hello python') a.print_abc() b.print_abc() 続き $ python3 class_var_const.py abc abc hello python hello python /chapter5/class_var_const.py コンソール出⼒
  202. クラスメソッド (1/2) • 「クラスメソッド」はクラス外から直接「クラス名.メソッド名()」 として呼び出せる特別なメソッド • メソッド前に「@classmethod」と「アノテーション」を加える • クラスメソッド内でインスタンス変数や通常のメソッドは使えない class

    MyClass: def __init__(self): self.a = 'aaa' @classmethod def method1(cls): print('class method') def method2(self): print('instance method') # インスタンス化してからクラスメソッドを呼び出す mc = MyClass() mc.method1() mc.method2() # インスタンス化せずにメソッドを呼び出す MyClass.method1() MyClass.method2() 続き /chapter5/method.py
  203. クラスメソッド (2/2) • メソッド呼び出し可否のまとめ • インスタンスでクラスメソッド: 呼び出せる • インスタンスで通常メソッド: 呼び出せる

    • クラス名でクラスメソッド: 呼び出せる • クラス名で通常メソッド: 呼び出せない(下記エラー) • クラスメソッドに似た「スタティックメソッド」もある(割愛) $ python3 method.py class method instance method class method Traceback (most recent call last): File "method.py", line 19, in <module> MyClass.method2() TypeError: method2() missing 1 required positional argument: 'self' コンソール出⼒ クラス名でメソッドを 呼び出そうとしてエラー
  204. クラスの継承 • 「継承」はクラスAの特徴をクラスBに引き継がせる機能 • 継承元を「親クラス」、親を継承する側を「⼦クラス」と呼ぶ • 基本機能を持つ親クラスを⼦クラスが継承して拡張する使い⽅ • ⼦クラスのクラス名の後のカッコに親クラス名を書く class

    ParentClass: def method1(self): print('parent method') class ChildClass(ParentClass): def method2(self): print('child method') cc = ChildClass() cc.method2() cc.method1() $ python3 succession.py child method parent method ⼦クラスが親クラスのメソッドも呼び出せている /chapter5/succession.py コンソール出⼒
  205. コラム: 初⼼者はあまり継承を使わない? • クラスAにクラスBの機能を取り込む際に何も考えずに継承を使うの は間違った使い⽅。継承は「Reader -> TextReader, ImageReader」といったように親を⼦がより詳細化する際に使う • 単純に機能だけを使いたければクラスA内でクラスBを使えばよい

    • 別クラスの機能を取り込むことを「委譲(デリゲーション)」という class ClassA: def __init__(self): self.class_b = ClassB() def use_class_b(self): self.class_b.print_hello() class ClassB: def print_hello(self): print('hello') class_a = ClassA() class_a.use_class_b() /chapter5/define_instance.py $ python3 delegation.py hello コンソール出⼒
  206. • 継承とデリゲーションの使い所について説明してください • Pythonのアノテーションがなにか、他にどのようなものがある か調べてみてください 演習

  207. モジュールを利⽤しよう CHAPTER 6 1. モジュールを利⽤する 2. ⾃分でモジュールを作成する 3. 標準ライブラリを利⽤する 4.

    外部パッケージを利⽤する
  208. モジュールを利⽤する • このセクションで学ぶこと • モジュールによるプログラムの整理 • 組み込みモジュール • 標準ライブラリ •

    外部パッケージ • ⾃作のモジュール • モジュールとクラスの違い • モジュールを使ってみよう • モジュール内のクラスの利⽤ • 複数のモジュールを組み込む • モジュール名を付けずに関数やクラスを呼び出す • コラム: from⽂の問題点 SECTION 01
  209. モジュールによるプログラムの整理 • 「モジュール」はプログラムが書かれたファイルのこと • 巨⼤な1つのファイルに全てを書くのではなく、分類に沿って プログラムを複数ファイルに分けることで全体を整理できる • 「パッケージ」は複数のモジュールをおさめるディレクトリ • モジュールは以下の以下図の4つに分類できる

  210. 組み込みモジュール • 「組み込みモジュール」はPythonがデフォルトで読み込む • print関数などの特に宣⾔なく利⽤できる機能が格納されている

  211. 標準ライブラリ • 「標準ライブラリ」はPythonをインストールすると⾃動で付属 してくるモジュール群 • プログラム内で利⽤する宣⾔をすると、その内部で定義されて いる関数やクラスが利⽤できるようになる

  212. 外部パッケージ • 「外部パッケージ」はPythonに標準で付属しないモジュール • 「pipコマンド」でインターネット上のリポジトリからインス トールをすることで使えるようになる • インストール後は標準ライブラリと同じように利⽤可能となる

  213. ⾃作のモジュール • 1つのファイルに収まりきらないコードを分割して作成する • Pythonでは可能な限り⾃分では難しい処理を書かずに標準ライ ブラリや外部パッケージを繋ぐ書き⽅が⼀般的

  214. モジュールとクラスの違い • モジュールもクラスもプログラムを整理する仕組み • モジュールはクラスよりも⼤きい単位でのコードの分割 • 1つのモジュール内に複数のクラスを含めることができる

  215. モジュールを使ってみよう • 数学関係のモジュール「math」(標準ライブラリ)を利⽤する • モジュール利⽤の宣⾔: import モジュール名 • モジュールの関数などの利⽤: モジュール名.関数()

    • 宣⾔はプログラムファイルの先頭周辺で⾏なうのが⼀般的 # mathモジュールの読み込み import math # mathモジュールのceil関数の利⽤ a = math.ceil(5.4) print(a) # mathモジュールのfloor関数の利⽤ print(math.floor(5.4)) $ python3 math_01.py 6 5 モジュールを利⽤する前にimportしないと エラーになる。 プログラムの冒頭でimportするのが慣習 /chapter6/math_01.py コンソール出⼒
  216. モジュール内のクラスの利⽤ • ⽇時を扱うdatatimeモジュールを使う • モジュールのクラスの利⽤: モジュール名.クラス名 import datetime now =

    datetime.datetime.now() print(now) >>> import datetime >>> datetime <module 'datetime' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/datetime.py'> >>> datetime.datetime <class 'datetime.datetime'> >>> datetime.datetime.now <built-in method now of type object at 0x10b546678> $ python3 datetime_01.py 2020-04-17 14:44:45.660410 /chapter6/datetime_01.py 「datetime.datetime.now」は「モジュール名.クラス名.メソッド名」 コンソール出⼒
  217. 複数のモジュールを読み込む • 必要なモジュールを1⾏ごと宣⾔するのが⼀般的 • 1⾏にまとめて宣⾔することもできる • 利⽤しないモジュールは宣⾔しないこと import math import

    time, datetime print(datetime.datetime.now()) time.sleep(3) print(datetime.datetime.now()) $ python3 math_datetime_01.py 2020-04-17 14:55:04.546417 2020-04-17 14:55:07.550372 /chapter6/math_datetime_01.py コンソール出⼒
  218. モジュール名を付けずに関数やクラスを呼び出す • fromで宣⾔するとモジュール名を省略して利⽤できる • from モジュール名 import クラス名や関数名 • from

    モジュール名 import *(全て) from math import ceil from time import * print(ceil(5.4)) sleep(1) print(floor(5.3)) $ python3 from_import_01.py 6 Traceback (most recent call last): File "from_import_01.py", line 6, in <module> print(floor(5.3)) NameError: name 'floor' is not defined /chapter6/from_import_01.py コンソール出⼒ importで指定したクラスや関数のみ読み込み モジュールの全てのクラスや関数を読み込み 読み込んでいないmathのfloorを 呼び出そうとしたためエラー
  219. コラム: from⽂の問題点 • fromで*(ワイルドカード)指定するのは⼿間がかからなくて簡単 • クラスや関数を多いと「関数やクラスがどのモジュールに属し ているかが分かりにくくなる」という問題がある • from⽂の使い所 •

    短いスクリプトなどで保守されない場合は使って問題ない • メンテされる⼤きめのプログラムではきちんとimport⽂を 使って宣⾔する
  220. • 「組み込みモジュール」「標準ライブラリ」「外部パッケー ジ」の違いについて説明してください • 標準ライブラリの利⽤演習 • jsonモジュールをimportしてください • 以下のdictを作成してください。{'apple':'red', 'banana':'yellow'}

    • json.dumps(dictオブジェクト)で辞書データを⽂字列型の JSONに変換してください • json.loads(⽂字列型のJSON)で辞書データを得てください • JSONはPythonに限らずマシン間やサービス間でのやりとり に多⽤されるデータ構造なので調べてみてください。 演習
  221. ⾃分でモジュールを作成する • このセクションで学ぶこと • モジュールは2つの種類に分けて書く • モジュールを作成する • モジュールが組み込まれる流れ •

    モジュールの中⾝と開始条件 • 定義と実⾏コードの分離 SECTION 02
  222. モジュールは2つの種類に分けて書く • タイプ1: システム特有の汎⽤的な処理をまとめたモジュール。 ⾃作ライブラリに近く、他のプロジェクトでも再利⽤可能 • タイプ2: タイプ1のモジュールを使ってシステムを形作るモ ジュール。汎⽤処理はタイプ1に押し込むこと。 タイプ1のモジュールは

    機能ごとに別モジュールに 分割することが好ましい
  223. モジュールを作成する • モジュールA(main.py)がモジュールB(myutil.py)を使う • 2つのファイルは同じフォルダに格納する • ファイルがあるフォルダに移動してからプログラムを呼び出し print('main.py start') import

    myutil print('main.py after import') def main_test(): print('main_test() called') main_test() myutil.myutil_test() print('main.py end') print('myutil.py start') def myutil_test(): print('myutil_test() called') print('myutil.py end') $ python3 main.py main.py start myutil.py start myutil.py end main.py after import main_test() called myutil_test() called main.py end /chapter6/main-myutil1/main.py /chapter6/main-myutil1/myutil.py 同じフォルダに使う側と使われる側の Pythonプログラム(モジュール)を置く。 そのフォルダでプログラムを起動 コンソール出⼒
  224. モジュールが読み込まれる流れ • 起動したファイルの⽂頭から読まれる • 途中でimportやfrom⽂があると指定されたモジュールから先に 読み込み処理をおこなう

  225. モジュールの中⾝と開始条件 • 複数のモジュールから構成されるプログラムで最初に呼び出さ れるモジュールを「エントリポイント」と呼ぶ • エントリポイント以外では実⾏処理は書かないことが期待され る。つまり定数や関数、クラスの宣⾔のみをおこなう

  226. 定義と実⾏コードの分離 (1/2) • エントリポイント以外では定義のみ⾏い処理は実⾏させない • 「if __name__ == ' __main__

    ':」という条件式を使う • 特殊属性 __name__ にはエントリポイントの場合は 「'__main__'」が、それ以外はモジュール名が⼊る • __name__ が'__main__'の場合にのみ処理を実⾏させる import myutil def start(): myutil.myutil_test() # エントリポイントの場合の処理 if __name__ == '__main__': print('main.py is entry point') start() この条件はこのプログラムファイルが エントリポイントの場合だけ満たされる /chapter6/main-myutil2/main.py
  227. 定義と実⾏コードの分離 (2/2) import myutil def start(): myutil.myutil_test() # エントリポイントの場合の処理 if

    __name__ == '__main__': print('main.py is entry point') start() def myutil_test(): print('myutil_test() called') print('__name__ of myutil : ' + __name__) # エントリポイントの場合の処理 if __name__ == '__main__': print('myutil.py is entry point') myutil_test() $ python3 main.py main.py is entry point myutil_test() called __name__ of myutil : myutil $ python3 myutil.py myutil.py is entry point myutil_test() called __name__ of myutil : __main__ /chapter6/main-myutil2/main.py /chapter6/main-myutil2/myutil.py コンソール出⼒ コンソール出⼒ 他から使われるモジュールではエントリポイントを 「モジュールのテストの実施」に使うとよい。 モジュールレベルでの完成度が得られるまでテストする myutilの実⾏処理は動作していない
  228. • モジュール mymath.py を作成して⼩数点を受け取る「切り下 げ: floor」と「切り上げ: ceil」を関数として作成してください。 • ヒント: 切り下げはint型への変換、切り上げは「もとの値と切

    り下げ値が同⼀なら切り下げ値、そうでなければ切り下げ+1」 で実装できます。⾯倒ならmathモジュールを使ってください • 5.1 -> 切り下げ:5, 切り上げ6 • 5.0 -> 切り下げ:5, 切り上げ5 • 等号演算⼦(==)で5.0と5を⽐較するとTrueになる • main.py モジュールで上記のmymathをimportし、切り上げと 切り下げの計算を確認してください • main.pyではエントリポイントとして起動された時だけ上記処 理を実施するために「if __name__ == '__main__': 」を使って ください 演習
  229. 標準ライブラリを利⽤する • このセクションで学ぶこと • 時間関連の処理をおこなうtimeモジュール • 時間関連の処理をおこなうdatetimeモジュール • 乱数を⽣成するrandomモジュール SECTION

    03
  230. 時間関連の処理を⾏うtimeモジュール • 時間を扱う基本的な処理 • time.sleep(x): x秒のスリープ • time.time(): 現在のUNIX時間(世界標準時の1970年1⽉1⽇から 何秒経過したか)を取得する

    • ある作業の前後で時間を取得し差分から実⾏時間を測定できる import time start = time.time() print(start) time.sleep(10) end = time.time() print(end) print(end - start) $ python3 time_01.py 1587107549.013738 1587107559.0178628 10.004124879837036 /chapter6/time_01.py コンソール出⼒
  231. 時間関連の処理を⾏うdatetimeモジュール • 時刻を扱うモジュール。⼈間の時間(2020年4⽉17⽇ 16:00な ど)はtimeではなくdatetimeが使いやすい • datetime.datetime.today(): 現在時刻の取得し、datetimeイン スタンスを返す •

    datetimeインスタンスには様々なメソッドと変数がある $ python3 datetime_02.py 2020-04-17 16:16:31.147644 2020/4/17 16:16:31 import datetime now = datetime.datetime.today() print(now) print('{}/{}/{} {}:{}:{}'.format(now.year, now.month, now.day, now.hour, now.minute, now.second)) /chapter6/datetime_02.py コンソール出⼒
  232. 乱数を⽣成するrandomモジュール • 乱数(ランダムな値)を⽣成するモジュール • random.random(): 0から1のあいだのランダムな⼩数を得る • random.randint(x, y): 引数のあいだにあるランダムな整数を得る

    • random.shuffle(): 引数のリスト要素をランダムに並び替える import random print(random.random()) print(random.randint(0, 100)) import random numbers = list(range(10)) print(numbers) random.shuffle(numbers) print(numbers) $ python3 random_01.py 0.2799910238537131 89 $ python3 random_02.py [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [4, 9, 3, 7, 1, 6, 5, 2, 0, 8] /chapter6/random_01.py /chapter6/random_02.py コンソール出⼒ コンソール出⼒
  233. • 3章の⾃作のソート関数を⾃作モジュールのmysortに定義して、 簡単なリストがきちんとソートされるか確認してください • randomモジュールを使って「0から100万」まででランダムに ⽣成した数値を1000個持つリスト⽣成してください • ⾃作の関数とPythonが提供するsorted関数で昇順ソートしてく ださい •

    Timeモジュールを使って⾃作のsort関数とPythonが提供する sort関数の処理時間を⽐較計測してください 演習
  234. 外部パッケージを利⽤する • このセクションで学ぶこと • 外部パッケージでPythonに機能を追加する • パッケージをインストールする • パッケージを利⽤する •

    コラム: ライブラリの使い⽅と探し⽅ SECTION 04
  235. 外部パッケージでPythonに機能を追加する • 標準ライブラリにない処理であっても⼀般的な処理(たとえば後 述するHTTPの操作)は外部パッケージに多く存在する • Python Package Indexにパッケージが集積されている • 有名なライブラリは信頼性が⾼いが無名なものは利⽤に注意

  236. パッケージをインストールする • Pythonインストール時に付属する「pipコマンド」を使う (Linuxのyumやaptに相当する) • Windows: pip install <パッケージ名> •

    Mac: pip3 install <パッケージ名> PS C: \Users\yito8> pip install requests Collecting requests Using cached requests-2.13.0-py2.py3-none-any.whl Installing collected packages: requests Successfully installed requests-2.13.0 $ pip3 install requests Collecting requests Using cached .../requests-2.23.0-py2.py3-none-any.whl Installing collected packages: requests Successfully installed requests-2.23.0 Windowsでのpipを使ったrequestsのインストール Macでのpipを使ったrequestsのインストール
  237. パッケージを利⽤する • pipでインストールしたパッケージは標準ライブラリと同じく import⽂もしくはfrom⽂で使える • インストールしていないパッケージをimportするとエラー import requests response =

    requests.get('http://www.yahoo.co.jp/') print(response.text) $ python3 requests_01.py <!DOCTYPE html><html lang="ja">... /chapter6/requests_01.py コンソール出⼒
  238. コラム: ライブラリの使い⽅と探し⽅ • ⾃分で特定の機能を実装する前に有名なパッケージがないか調 べてみるのがよい。低レイアの実装は可能な限り避けること • Googleで「python ライブラリ <やりたいこと>」と調べると パッケージの利⽤法ページやQAページがヒットすることが多い

    • 標準ライブラリの利⽤法はPythonの公式ドキュメントにある
  239. • pip(pip3)でcowsayパッケージをインストールしてください • インタプリタでcowsay.関数名(⽂字列)を実⾏してください • 関数⼀覧[ʻbeavisʼ, ʻcheeseʼ, ʻdaemonʼ, ʻcowʼ, ʻdragonʼ,

    ʻghostbustersʼ, ʻkittyʼ, ʻmeowʼ, ʻmilkʼ, ʻstegosaurusʼ, ʻstimpyʼ, ʻturkeyʼ, ʻturtleʼ, ʻtuxʼ] 演習 >>> import cowsay >>> cowsay.cow('hello python') ____________ < hello python > ============ \ \ ^__^ (oo)\_______ (__)\ )\/\ ||----w | || ||
  240. ファイルの読み書きと例外処理を⾏おう CHAPTER 7 1. テキストファイルの読み書きを⾏う 2. 予期しないエラーに例外処理で対応する 3. Pythonで⽇本語の⽂字列を扱う 4.

    プログラムへのユーザー⼊⼒を利⽤する
  241. テキストファイルの読み書きを⾏う • このセクションで学ぶこと • ファイルの読み書き処理はテキストエディタと同じ • テキストファイルの読み込み • ファイルのクローズ •

    ファイルの書き込み処理 • ファイルの追記処理 • バイナリデータの読み書き処理 • コラム: バイナリデータの処理 SECTION 01
  242. ファイルの読み書き処理はテキストエディタと同じ • ファイル操作の流れ 1. ファイルをモード(Read/Write/Append)を指定して開く 2. ファイルを操作する 3. ファイルを閉じる •

    Pythonでファイルの読み書きには「open」関数を使う • 関数の返り値のファイルオブジェクトのメソッドでファイル操作 hello world hello python fin = open('hello.txt', 'r') print(fin) $ python3 open_01.py <_io.TextIOWrapper name='hello.txt' mode='r' encoding='UTF-8'> コンソール出⼒ /chapter7/hello.txt /chapter7/open_01.py
  243. テキストファイルの読み込み • open関数の第⼆引数を「r」にして読み込み専⽤のファイルオ ブジェクトを取得する • 読み込みモードでの主要な操作 • readメソッド: ファイルの内容を全て読み込む •

    forループ: ファイルの1⾏ずつループ処理する。省メモリ fin = open('hello.txt', 'r') text = fin.read() print(text) hello world hello python $ python3 open_02.py hello world hello python fin = open('hello.txt', 'r') i = 1 for line in fin: line = line.rstrip() print('{} {}'.format(i, line)) i += 1 $ python3 open_03.py 1 hello world 2 hello python コンソール出⼒ コンソール出⼒ /chapter7/hello.txt /chapter7/open_02.py 1⾏ずつ⾏番号とテキストを出⼒: /chapter7/open_03.py 巨⼤なファイルには 必ずforループを使う
  244. ファイルのクローズ • OSのリソースの開放と「書き込み処理を確実にする」ために ファイル操作終了後にファイルオブジェクトをクローズする • 「close」メソッドを使う fin = open('hello.txt', 'r')

    text = fin.read() fin.close() hello world hello python $ python3 close_01.py コンソール出⼒ /chapter7/hello.txt /chapter7/close_02.py
  245. ファイルの書き込み処理 • openする際に「w(write)」モードを指定する • オープン時にファイル内容が全削除される • writeメソッドでテキストを書き込む • 改⾏は付与されないので必要ならテキストに「\n」を追加 fout

    = open('test.txt', 'w') fout.write('write text1\n') fout.write('write text2\n') fout.close() $ python3 write_01.py write text1 write text2 コンソール出⼒ /chapter7/test.txt /chapter7/write_01.py
  246. ファイルの追記処理 • すでにあるファイルの末尾にデータを書き込むには 「a(append)」を指定して追記モードでファイルを開く • 開いたあとの操作は「w」モードと同じ fout = open('test.txt', 'a')

    fout.write('write text3\n') fout.close() write text1 write text2 write text3 write text1 write text2 write text3 write text3 $ python3 write_02.py $ python3 write_02.py コンソール出⼒ /chapter7/test.txt(1回⽬の実⾏) /chapter7/test.txt(2回⽬の実⾏) /chapter7/write_02.py
  247. バイナリデータの読み書き処理 • 画像などのバイナリデータはモードに「b(binary)」を加える • 読み込みモード: 「rb」 • 書き込みモード: 「wb」 fi

    = open('sample.png', 'rb') image = fi.read() fi.close() fo = open('test.png', 'wb') fo.write(image) fo.close() $ python3 write_03.py コンソール出⼒ /chapter7/sample.png /chapter7/test.png 画像ファイルのコピー: /chapter7/write_03.py
  248. コラム: バイナリデータの処理 • バイナリデータを直接ユーザー操作することは少ない • たとえばPILモジュールによる画像操作(サイズを⼩さくする) 1. ファイルからバイナリデータを読み込む 2. ライブラリにバイナリデータを渡す

    3. ライブラリでデータ加⼯(画像サイズを⼩さくする) 4. バイナリデータをライブラリから取得 5. バイナリデータをファイルに書き込む • 「io.BytesIO」でバイナリをファイルに⾒せる処理をバイナリ 系の操作ではよく使う。ファイルパスが求められるところにバ イナリを与えたり、ファイルに書き出すのではなくバイナリを 書き出すなどができる データ操作は ライブラリ 任せ
  249. • テキストファイルを読み込んで、各⾏を逆に出⼒したファイル を書き出す。各⾏処理はforループがおすすめ。 • 発展課題: PILモジュールをインストールして画像サイズを編集 してください。 • 上記のファイル名指定での動作を確認したら、ライブラリに ファイル名を与えるかわり「io.Bytes()」でライブラリにバイ

    ナリデータを渡して、ライブラリからバイナリデータを受け 取ってファイルに書き出してください 演習 abcd efgh ijkl dcba hgfe lkji 読み込むファイル 出⼒するファイル >>> 'abc'[::-1] 'cba' ヒント: ⽂字列の反転処理
  250. 予期しないエラーに例外処理で対応する • このセクションで学ぶこと • 例外とは • 2種類の例外 • try/exceptによる例外処理 •

    例外の詳細を取得する SECTION 02
  251. 例外とは • 「例外」はプログラムの予期しない動作で発⽣するエラー • エラーと例外(英語ではException)はほぼ同じ意味 • たとえば存在しないファイルを読もうとすると例外が発⽣する fin = open('abc.txt',

    'r') for line in fin: print(line) fin.close() print('finished') $ python3 exception_01.py Traceback (most recent call last): File "exception_01.py", line 1, in <module> fin = open('abc.txt', 'r') FileNotFoundError: [Errno 2] No such file or directory: 'abc.txt' /chapter7/exception_01.py コンソール出⼒
  252. 2つのタイプの例外 • 例外はおおまかに以下の2つに分類できる • プログラムのバグから発⽣する例外。⽂法エラーや0除算など • 外部要因で発⽣する例外。アクセス先サーバーのダウンなど • バグ起因の例外はプログラムを修正して対処することが必要 •

    外部要因の例外は防げないので「例外処理(失敗したときの処理)」 を定義して対処する
  253. try/exceptによる例外処理 (1/2) • 例外発⽣時に処理を継続するために「try/except」⽂を使う • try: 例外が発⽣する可能性がある場所 • except: try内で例外が発⽣した場合におこなわれる処理

    try: file_name = 'test.txt' print('ファイルの読み込み開始') fin = open(file_name, 'r') fin.read() fin.close() print('読み込み成功') except: print('エラーが発⽣') print('プログラムが終了') $ python3 exception_02.py ファイルの読み込み開始 読み込み成功 プログラムが終了 $ python3 exception_02.py ファイルの読み込み開始 エラーが発⽣ プログラムが終了 存在する ファイル 存在しない ファイル コンソール出⼒ コンソール出⼒ /chapter7/exception_02.py エラーが発⽣してもプログラム最後まで実施されている
  254. • tryブロック内の処理はエラー発⽣箇所以降は実⾏されない • exceptブロックはエラーが発⽣しなければ実⾏されない • try/except後の処理はエラーの有無に関わらず実⾏される try/exceptによる例外処理 (2/2)

  255. 例外の詳細を取得する (1/2) • except⽂で例外を「例外クラス」の変数に補⾜できる • 例外クラスの最も⼀般的なものは「Exception」 • 例外クラスの種類に応じた例外処理の定義なども可能で、可能 ならより詳細な例外クラスで実装することを推奨(割愛) try:

    fin = open('test999.txt', 'r') fin.close() except Exception as e: print('エラーが発⽣') print(e) $ python3 exception_03.py エラーが発⽣ [Errno 2] No such file or directory: 'test999.txt' /chapter7/exception_03.py コンソール出⼒
  256. 例外の詳細を取得する(2/2) • 「traceback」モジュールを使うとエラー発⽣時に出⼒されて いたメッセージのほぼ全てを補⾜できる • エラー発⽣箇所がファイルと⾏単位で分かる import traceback try: fin

    = open('test999.txt', 'r') fin.close() except: print('エラーが発⽣') error_text = traceback.format_exc() print(error_text) $ python3 exception_04.py エラーが発⽣ Traceback (most recent call last): File "exception_04.py", line 4, in <module> fin = open('test999.txt', 'r') FileNotFoundError: [Errno 2] No such file or directory: 'test999.txt' コンソール出⼒ /chapter7/exception_04.py 中級者向け: 例外処理に慣れたら例外クラスを 指定した「予測していた」例外処理に加えて、 予測していなかった例外処理をExceptionなどの 上位の例外クラスでtraceback付きで処理する
  257. • requestsモジュールのgetを例外処理でラップした関数を作成 してください(6章に従ってインストールが必要) • 返り値はタプルで(成功したか, レスポンスのテキスト)とします • 例外が発⽣した場合はtracebackをプリントして、(False, '') を返す

    • レスポンスに問題がある場合は(False, '')を返す • 問題がない場合(True, テキスト)を返す • リクエストレスポンスに問題があるかないかは「レスポンスオ ブジェクト.ok」で調べられます • わざと「存在しないサイトにアクセス」「存在するサイトの存 在しないURLにアクセス」をしてみてください 演習
  258. Pythonで⽇本語の⽂字列を扱う • このセクションで学ぶこと • ⽂字コードとは • プログラムファイルの⽂字コード • コラム: python2の⽂字コード

    • 様々な⽂字コードのファイルの読み書き SECTION 03
  259. ⽂字コードとは • テキストファイル内の⽂字列も01で構成されている • 特定の01の組み合わせが「a」や「あ」と解釈されている • 同じ⽂字でも「⽂字コード」によって01の組み合わせが異なる • 16進数(0,1,...9,A,B,C,D,E)の1桁で2進数4桁「0000-1111」を表 現できるため、読みやすさで⽂字コードを含むバイナリ表記に

    は16進数を使うのが⼀般的 ⽂字コード 「a」の⽂字コード 「あ」の⽂字コード UTF-8 0x61 0x82A0 Shift-JIS 0x61 0xA4A2 EUC-JP 0x61 0xE38182
  260. プログラムファイルの⽂字コード • Pythonの標準⽂字コードはUTF-8。これを使うのが基本 • 諸事情で他の⽂字コードを使う場合はプログラムの冒頭で「ど の⽂字コードでプログラムを書いているか」を宣⾔する # -*- coding: shift-jis

    -*- print('こんにちは') $ python3 encoding_01.py こんにちは コンソール出⼒ Shift-Jisで書かれたプログラム: /chapter7/encoding_01.py プログラムの⽂字コードの指定。 プログラムが指定した⽂字コードで なければエラーが発⽣する
  261. コラム: python2の⽂字コード • Python2のデフォルト⽂字コードはASCII(アルファベットのみ) • ⽇本語及びマルチバイト⽂字を使うのであれば⽂頭での⽂字 コードの宣⾔がUTF-8でも必要 • ⾊々と⾯倒なので⽇本語を使うのであればPython3を使うべき

  262. 様々な⽂字コードのファイルの読み書き (1/2) • OSによってopen関数が想定するデフォルト⽂字コードが異なる • Windows(⽇本語環境): Shift-JIS • Mac: UTF-8

    fin_sjis = open('sjis.txt', 'r') print(fin_sjis.read()) fin_sjis.close() fin_utf8 = open('utf8.txt', 'r') print(fin_utf8.read()) fin_utf8.close() $ python3 encoding_02.py Traceback (most recent call last): File "encoding_02.py", line 2, in <module> print(fin_sjis.read()) File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/codecs.py", line 322, in decode (result, consumed) = self._buffer_decode(data, self.errors, final) UnicodeDecodeError: 'utf-8' codec can't decode byte 0x82 in position 0: invalid start byte • デフォルト⽂字コードと異なる ファイルを⽂字コード指定なしに openするとエラー コンソール出⼒ /chapter7/encoding_02.py MacでUTF-8を期待していたのにShift-Jisをオープンしたのでエラーとなっている
  263. 様々な⽂字コードのファイルの読み書き (2/2) • open関数のencode引数で⽂字コードを指定可能 • マルチプラットフォーム環境も考慮すると以下を推奨 • テキストファイルの⽂字コードにはUTF-8を利⽤ • 移植性を考えてMacであってもファイル読み込み時の

    encodeオプションにUTF-8を指定しておく • writeモードではopen時に指定した⽂字コードでファイルが書 き出される fin_sjis = open('sjis.txt', 'r', encoding='shift-jis') print(fin_sjis.read()) fin_sjis.close() fin_utf8 = open('utf8.txt', 'r', encoding='utf-8') print(fin_utf8.read()) fin_utf8.close() $ python3 encoding_03.py あいうえお かきくけこ あいうえお かきくけこ コンソール出⼒ /chapter7/encoding_03.py
  264. • 中に書かれている⽂字コードが不明なファイルの⽂字コードを 特定するプログラムを作成してください • UTF-8, Shift-JIS, EUC-JPの3つを判定するものとします • AsciiのテキストはUTF-8に分類されるとします •

    ヒント: 指定した⽂字コードで読み込めればその⽂字コード、 エラーがおきればその⽂字コードでないと分かります • 本書籍で提供されているUTF-8とShift-Jisのサンプルファイル を使って正しく判別できるか確認してください 演習
  265. プログラムへのユーザー⼊⼒を利⽤する • このセクションで学ぶこと • コマンドライン引数による⼊⼒ • コマンドライン引数の利⽤例 • input関数での標準⼊⼒ •

    input関数の利⽤例 • コラム: コマンドライン引数 vs 標準⼊⼒ SECTION 04
  266. コマンドライン引数による⼊⼒ • プログラムにユーザー⼊⼒を与える場⾯は多い • 解析プログラムで解析するデータのファイル • 接続先IPやパスワードなど • プログラム内に直接定数で定義するよりユーザーに⼊⼒させた ほうがプログラム修正がいらないので利⽤が簡単

    • コンソールでプログラム起動時に与えるパラメーター(コマンド ライン引数)を「sys.argv」でリスト形式で取得できる $ python3 argument_01.py abcd efgh ['argument_01.py', 'abcd', 'efgh'] import sys print(sys.argv) 起動時にプログラム名に加えて「abcd」「efgh」が与えられている。 sys.argv(リスト)にプログラムファイルと コマンドライン引数が順番に格納されている コンソール出⼒ /chapter7/argument_01.py
  267. コマンドライン引数の利⽤例 • 指定したファイルを読み込むプログラム • コマンドライン引数を使うコツ • 引数が指定された数か最初にチェックする • sys.argvの要素の値を分かりやすい定数に代⼊する import

    sys if len(sys.argv) < 2: print('Error. please input file name') exit() FILE_NAME = sys.argv[1] fin = open(FILE_NAME, 'r') print(fin.read()) fin.close() $ python3 argument_03.py hello.txt hello world hello python hello world hello python コンソール出⼒ /chapter7/argument_03.py /chapter7/hello.txt
  268. input関数での標準⼊⼒ • 「input関数」で標準⼊⼒受け付け(ユーザーのキーボード⼊⼒ を受け付ける)状態となる • エンター(リターン)ボタンが押されたら⼊⼒終了 print(1) a = input('何か⽂字を⼊⼒してください:')

    print('⼊⼒値:' + a) print(2) $ python3 input_01.py 1 何か⽂字を⼊⼒してください: $ python3 input_01.py 1 何か⽂字を⼊⼒してください:hello ⼊⼒値:hello 2 コンソール出⼒ 「hello」と⼊⼒しエンターキー /chapter7/input_01.py
  269. input関数の利⽤例 • パラメーター⼊⼒を対話式に⾏なうプログラム • IPやパスワードなどを順番に⼊⼒させる • 設定項⽬の番号を⼊⼒させ、各項⽬でIPやパスワードを⼊⼒ • プログラムをあえて⼀時中断させる⽬的 •

    デモやテストのステップごとに⽌めて結果を表⽰。確認を終 えたら次のプログラムに向かう file_name = input('please input filename: ') fin = open(file_name, 'r') print(fin.read()) fin.close() $ python3 input_02.py please input filename: hello.txt hello world hello python コンソール出⼒ ファイル名を聞いて、それを出⼒するプログラム: /chapter7/input_02.py
  270. コラム: コマンドライン引数 vs 標準⼊⼒ • Pythonのプログラムはシェルスクリプトやバッチなどから呼び 出されることも多い • 標準⼊⼒はユーザーの敷居は低いかもしれないが、他のプログ ラムから使いにくくなる

    • コマンドライン引数は呼び出せば動くので、他のプログラムか ら使いやすい • 特別な理由がなければコマンドライン引数でパラメーターを⼊ ⼒させるのがよい • 第三の⼿法として「環境変数でのパラメーター指定」なども使 われることがある
  271. • コマンドライン引数と、input関数でそれぞれ以下を実現するプ ログラムを作成してください • 「数値1, 計算記号, 数値2」を受け取る • 対応する計算記号は +,

    -, *, / の4つ • 数値1と数値2を与えられた計算記号で計算した結果をprint 出⼒する • ヒント1: 数値は⽂字列からfloatにキャストする • ヒント2: 計算記号の値に応じてif/elseで処理を変える 演習
  272. アプリケーションを作成しよう CHAPTER 8 1. アプリケーション開発の流れを知る 2. 重要箇所をテスト実装する 3. 本番のプログラムを作る

  273. アプリケーション開発の流れを知る • このセクションで学ぶこと • プログラム開発の計画を作る • ⽬的を実現するためになにが必要かまとめる • プログラム全体の流れを考える •

    コラム: 設計とフレームワーク SECTION 01
  274. プログラム開発の計画を作る • 題材:インターネットから複数の画像を集めるプログラムを作成 • アプリケーション開発には計画が必要 • 本章では以下のステップで開発を進めていく • ⽬的を実現するためには何が必要かまとめる •

    プログラム全体の流れを考える • プログラムの中の重要な箇所を試験的に作ってみる • プログラムの⼤枠を作る • コードに機能を追加していき設計や品質を向上させる
  275. ⽬的を実現するためになにが必要かまとめる • ⽬的: インターネットから画像を取得する • 必要なこと • 画像のURLを取得してダウンロード • 画像のURLはウェブサイトのHTMLに埋め込まれている

    • 埋め込まれているURLを「正規表現(後述)」で抽出する
  276. プログラム全体の流れを考える • 画像ファイルのURLを取得するウェブページのURLが必要 • ウェブページ1でウェブページと画像URLを集めたら、そこに あるウェブページ2で取得。次にウェブページ3と繰り返せる • 終了条件や同じURLの再取得を防ぐ⽅法を検討

  277. コラム: 設計とフレームワーク • ⼊⾨書は読んで理解できたが、実際にサンプル以上のプログラ ムを書けないという⼈が多い • フレームワークは「⼤枠のなかの処理を⾃分で実装する」とい う⽅式でシステムを作成するので、ライブラリを使って⾃分が 全てを設計するよりも「設計が簡単」 •

    ⾃分で設計をするのは慣れが必要なので、HTML/CSSを学んで 簡易ウェブフレームワークで簡単な動的なウェブサイトを作っ てみるとよいかも ライブラリ ライブラリ ライブラリ ⾃分で設計した⼤枠 作成したパーツ フレームワークが⽤意する⼤枠 作成したパーツ 作成したパーツ 独⾃設計のアプリ フレームワークに従うアプリ
  278. 重要箇所をテスト実装する • このセクションで学ぶこと • なぜテスト実装が必要なのか • URLを指定してHTMLを取得 • 正規表現でHTMLからURLを取得 •

    相対URLを絶対URLに変換 • URLが画像ファイルか否かを判定 • 画像ファイルを保存 SECTION 02
  279. なぜテスト実装が必要なのか • 開発スピードを向上させるため • ⼤きなサービスのなかで⼩さな1つの機能を0から開発するの は「起動」「準備(テスト値の⽤意など)」に時間がかかる • ⼩さなコードでエラーを繰り返しながら機能を実現させ、その あとで組み込めばトラブルが少ない •

    当初の想定と異なる場合があるため • 利⽤を想定していたライブラリが⽬的の機能を果たせない場合 などがある • 他を作り込んだうえで発覚すると修正が⼤変なので⼤枠を固め る前に可能な限りパーツを作っておく • すでに重要箇所が動いているとメンタル的に安⼼して開発できる
  280. URLを指定してHTMLを取得 • 本番プログラムは⼤きくて複雑なので、「本番でも使いやすい テスト⽤のコード(たとえば関数)」を作成するのがよい • HTMLの取得には6章のrequestsモジュールを利⽤ import requests def download_html(url):

    response = requests.get(url) html = response.text return html html = download_html('https://gihyo.jp/book/list') fout = open('sample.html', 'w', encoding='utf8') fout.write(html) fout.close() $ python3 get_images_01.py <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:og="http://opengraphprotocol.org/schema/" xmlns:fb="http://www.facebook.com/2008/fbml" xml:lang="ja" lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>書籍⼀覧新刊|技術評論社</title> <meta name="description" content="" />... URLを指定してHTMLを取得するコード: /chapter8/get_images_01.py 出⼒ファイル: sample.html コンソール出⼒
  281. 正規表現でHTMLからURLを取得(1/2) • 先に取得したHTML内にはURLが多数ある • ウェブサイトや画像のURLを抜き出す処理に正規表現を使う • 「正規表現」は 特定のパターンの⽂字列が含まれるかのチェック や抜き出し処理をする⼿法。他のプログラミング⾔語にもある •

    複雑な正規表現のパターンは検索するのが⼿っ取り早い。たとえ ば「Python 正規表現 URL」や「Python regex URL」など ... 複雑な正規表現は検索から 答えを発⾒
  282. 正規表現でHTMLからURLを取得(2/2) import re text = '<p>Hello World</p><a href="http://example.com">More Examples</a><a href="http://example2.com">Even

    More Examples</a>"' links = re.findall('<a href="?\'?([^"\'>]*)', text) print(links) $ python3 get_url_from_html.py ['http://example.com', 'http://example2.com'] import requests import re def get_urls(url): response = requests.get(url) html = response.text urls = re.findall('<a href="?\'?([^"\'>]*)', html) return urls urls = get_urls('https://gihyo.jp/book/list') print(urls) $ python3 get_images_02.py ['/book', '/site/inquiry', '/site/profile', … コンソール出⼒ コンソール出⼒ HTMLからURLを抜き出すプログラム: /chapter8/get_url_from_html.py 指定したURLにアクセスしてURLを抜き出すプログラム: /chapter8/get_images_02.py
  283. 相対URLを絶対URLに変換 • 絶対URL: https://gihyo.jp/news/info/2020/03/1301 • 相対URL(ドメインが省略): /news/info/2020/03/1301 • 相対URLは現在のURLを基準とした表記なので、プログラムで 使う場合は現在地に依存がない絶対URLへの変換が望ましい

    import urllib.parse def get_abs_url(current_url, url): abs_url = urllib.parse.urljoin(current_url, url) return abs_url print(get_abs_url('https://gihyo.jp/book/list', 'http://gihyo.jp/site/inquiry')) print(get_abs_url('https://gihyo.jp/book/list', '/book/2017/978-4-7741-8751-8')) print(get_abs_url('https://gihyo.jp/book/list', '2017/978-4-7741-8751-8')) $ python3 get_abs_url.py http://gihyo.jp/site/inquiry https://gihyo.jp/book/2017/978-4-7741-8751-8 https://gihyo.jp/book/2017/978-4-7741-8751-8 コンソール出⼒ 相対URLを絶対URLに変換するプログラム: /chapter8/get_abs_url.py
  284. URLが画像ファイルか否かを判定 • URLを以下の2種類のいずれか拡張⼦で判定する • 画像ファイル: 拡張⼦が「.jpg」「.png」「.gif」 • HTMLファイル: 画像ファイルでない場合全て •

    (厳密にはHTTPレスポンスのMIMEで判断することが望ましい) def check_url_type(url): if '.jpg' in url: print('jpg') elif '.png' in url: print('png') elif '.gif' in url: print('gif') else: print('html') urlの画像判定プログラム: /chapter8/check_url_type.py
  285. 画像ファイルを保存 • requestsで取得したレスポンスからデータを取得 • データをバイナリ書き込みモードでファイルに保存 import requests import os def

    save_image(url, filepath): # 画像データを取得 response = requests.get(url, stream=True) image_data = response.content fout = open(fpath, 'wb') fout.write(image_data) fout.close() URLの画像を保存する: /chapter8/save_image.py
  286. • このセクションで作成したプログラムを全て実⾏してみる • 関数定義のみで実⾏コードが書かれていないプログラムは、⾃ 分で実⾏コードを作成してください 演習

  287. 本番のプログラムを作る • このセクションで学ぶこと • クラスを設計する流れ • コンストラクタの実装 • メソッドの役割を決める •

    メインメソッドの実装 • 指定ページから絶対URL⼀覧を得るメソッドの実装 • 絶対URLを画像とHTMLに振り分けるメソッドの実装 • 画像データを保存するメソッドの実装 • メインプログラムの実⾏ • コラム: プログラムのテスト SECTION 03
  288. クラスを設計する流れ • 複雑なプログラムでは「関数(メソッド含む)が別の関数を呼び出 す」を繰り返すことで実現する • 関数間で全てのデータを引数で受け渡しするとカオスになるので、 クラスを使って共有データはインスタンス変数として定義する(詳 細な理由は5章を参照) • クラス設計

    • プログラムが必要とする情報はコンストラクタで受け取る • メソッド間で共有されるデータはコンストラクタでインスタン ス変数として定義する • 処理に応じてメソッドを分けて、中⼼となるメソッドが各機能 を担当するメソッドを呼び出すシンプルな処理の流れを作る
  289. このアプリケーションの設計概要 __init__(コンストラクタ) インスタンス変数の定義 run メインメソッド Whileループで集め 終わるまで繰り返す get_abs_url 指定URLから絶対値のURL群を取得 get_image_url_list

    URL群から画像のURL群を取得 save_images 画像URL群の画像をローカルに保存 実⾏ コード クラス定義 (1) (2) (3) (4) (5) (6) この章での実装順序
  290. コンストラクタの実装 • 引数 • save_dirpath: 画像保存場所 • start_page: 最初にアクセスするURL •

    maximum_download: 集める画像の枚数 import os import re import urllib import requests class ImageCrawller: def __init__(self, save_dirpath, start_page, maximum_download): self.save_dirpath = save_dirpath self.crawl_url_list = [start_page] self.stocked_url = set() self.maximum_download = maximum_download self.download_counter = 0 • インスタンス変数 • self.save_dirpath: 引数より • self.crawl_url_list: 次にアクセスするURLのリスト • self.stocked_url: すでにアクセスしたURLのセット • self.maximum_download: 引数より • self.download_counter: 何枚保存したか数える コンストラクタの定義: /chapter8/image_crawller_01.py
  291. メソッドの役割を決める • メソッドの分割について • ⼤きい: 処理が多すぎてメソッドの⾒通しが悪くなる • ⼩さい: メソッド間の呼び出しが多すぎて分かりにくい •

    適切な粒度(分割する⼤きさ)が必要 • 本章で作成するメソッド • コンストラクタ(作成済み) • 下記3つを束ねる中⼼となるメソッド(メインメソッド) • あるURLのHTMLに含まれる絶対URLをリストで返すメソッド • URLをHTMLと画像に振り分けるメソッド • イメージを保存するメソッド
  292. メインメソッドの実装 (1/2) • 荒削りでよいので、全体の処理の流れをコメント付きで書く • 細部を実装してからメインメソッドも微修正される • 実験的に主要な機能をテストしていないと設計しづらく、あと にプログラムの⼤きな修正が発⽣する可能性が⾼まる •

    プログラム(次ページ)の設計 1. 終了条件に合致していないか確認。合致していれば終了 2. URL回収⽤のウェブページURLをリストから取得 3. そのURLにアクセスして絶対URLのリストを取得 4. 絶対URLのリストを「画像」「ウェブページ」に分類 5. 画像のURLリストの画像を全て取得 6. 1に戻る(whileによる無限ループ)
  293. メインメソッドの実装 (2/2) def run(self): while True: # 処理1: 探索するURLがなければ終了。規定数以上を集めていても終了 if

    len(self.crawl_url_list) == 0: break if self.download_counter >= self.maximum_download: break # 処理2: 次に調べるHTMLのURLを取得 crawl_url = self.crawl_url_list.pop(0) # 処理3: HTMLページから絶対URLを抽出する urls = self.get_abs_urls(crawl_url) # 処理4: 絶対URLをHTMLかイメージかに分類する。イメージのリストを返す image_url_list = self.get_image_url_list(urls) # 処理5: リストに格納されたイメージを全て保存する self.save_images(image_url_list) print('Finished') メインメソッドの定義を追加: /chapter8/image_crawller_02.py
  294. 指定ページから絶対URL⼀覧を得るメソッドの実装 def get_abs_urls(self, url): try: # URLから⽂字列のHTMLを取得 response = requests.get(url)

    html = response.text # HTMLからURLを抜き出してリストに格納 relative_url_list = re.findall('<a href="?\'?([^"\'>]*)', html) # 相対URLを絶対URLに変換。HTTP/HTTPS以外のURLは除外 abs_url_list = [] for relative_url in relative_url_list: abs_url = urllib.parse.urljoin(url, relative_url) if abs_url.startswith('http://') or abs_url.startswith('https://'): abs_url_list.append(abs_url) return abs_url_list except Exception as e: print('Error: {}'.format(e)) return [] メソッドget_abs_urlsを追加: /chapter8/image_crawller_03.py
  295. 絶対URLを画像とHTMLに振り分けるメソッドの実装 def get_image_url_list(self, url_list): try: image_url_list = [] for url

    in url_list: if url in self.stocked_url: # すでに登録されたURLなので無視 continue if '.jpg' in url: image_url_list.append(url) elif '.png' in url: image_url_list.append(url) elif '.gif' in url: image_url_list.append(url) else: self.crawl_url_list.append(url) # 画像ファイルではないのでURL取得に使う self.stocked_url.add(url) # URLを登録。同じものは再登録しない return image_url_list except Exception as e: print('Error: {}'.format(e)) return [] メソッドget_image_url_listを追加: /chapter8/image_crawller_04.py
  296. 画像データを保存するメソッドの実装 def save_images(self, image_url_list): for image_url in image_url_list: try: #

    決められた回数以上のダウンロードをした場合は終了 if self.download_counter >= self.maximum_download: return # イメージを取得 response = requests.get(image_url, stream=True) image = response.content # イメージをファイルに保存 file_name = image_url.split('/').pop() save_path = os.path.join(self.save_dirpath, file_name) fout = open(save_path, 'wb') fout.write(image) fout.close() self.download_counter += 1 print('saved image: {}/{}' .format(self.download_counter, self.maximum_download)) except Exception as e: print('Error: {}'.format(e)) メソッドsave_imagesを追加: /chapter8/image_crawller_05.py
  297. メインのプログラムの実⾏ • プログラム最後に「if __name__ == ' __main__ ' :」を定義 if

    __name__ == '__main__': save_dirpath = 'test' start_page = 'https://gihyo.jp/book/list' maximum_download = 10 crawller = ImageCrawller(save_dirpath, start_page, maximum_download) crawller.run() $ python3 image_crawller_06.py saved image: 1/10 saved image: 2/10 saved image: 3/10 saved image: 4/10 saved image: 5/10 saved image: 6/10 saved image: 7/10 saved image: 8/10 saved image: 9/10 saved image: 10/10 Finished コンソール出⼒ アプリを動かす実⾏コードを追加: /chapter8/image_crawller_06.py
  298. コラム: プログラムのテスト • 数⼗⾏以上のコードがミスなく書けていると思わないこと • 「ビッグバンテスト」と呼ばれる全てを書き終わってから動かし てテストをすることは避けること • テストを使ってきちんと動くプログラムを書くコツ •

    モジュールの設計で役割ごとにプログラムファイルを分離 • 確実に動く⼩さなプログラムを開発してモジュールに組み込む • モジュール間の依存関係を減らしてモジュールレベルでテスト を実施できるようにする • 変更を繰り返した汚いコードは綺麗に書き直す • ユニットテストでテストを⾒える化する(中級者) • ⾃動化などでテストを勝⼿に⾛らせるようにする(上級者)
  299. • 最初にアクセスするページを変更してアプリケーションを⾃分 で起動してみる(ウェブサイトに過負荷を与えるのを避けるため ⼩規模のサイトは使わないでください) • 画像ではなくHTMLを集めて保存するプログラムを作成してく ださい • 発展課題: HTMLがすでに保存されているファイル名であれば

    名前に連番を付けるなどしてください 演習
  300. お悩み相談コーナー 教科書は理解したけど次のレベルに進めません!! おまけ 1. ⼊⾨者卒業: 本を読むよりコードを書くべし 2. 初級者卒業: 美しい設計を体と頭で覚える 3.

    中級者卒業: 開発はプログラミング以外にもある 4. 駆け出し編: インフラエンジニアという道もある 5. 歴史編: 開発とインフラの技術変遷
  301. ⼊⾨者卒業: 本を読むよりコードを書くべし • このセクションで学ぶこと • プログラミングのレベル • 包丁をにぎらず本ばかり読む駆け出し料理⼈ • やりたいことは書き始めてから考えよう

    • おすすめ1: Flaskによる簡易ウェブサービスの作成 • おすすめ2: Tkinterによるデスクトップアプリの作成 • おすすめ3: 業務向けの作業スクリプト作成 • 著者が興味でプログラムを書いた例 • ⼊⾨者卒業に難しい知識はいらない SECTION 01
  302. プログラミングのレベル • ドラクエと同じで「適切な場所(学習内容)」でレベル上げ • 低いレベルで難易度の⾼すぎるエリアには向かわないこと • 2010年以降は開発スタイルが⼤きく変わってきている ⼊⾨者 初級者 中級者

    中上級者 (オールラウンド型) 上級者 (プログラミング特化型) ⼊⾨書(2000円ぐらいの書籍)の レベルの内容を習得済み。 • 基礎⽂法はわかる • オブジェクト指向を使える • 簡単なスクリプトを書ける • 簡易フレームワーク習得 • ⾃分で簡単なアプリを作成できる ⾼度なプログラミング知識 • ⾃分で中規模アプリを作成できる • オブジェクト指向を設計可能 • フルスタックフレームワーク習得 • デザインパターン習得 • リファクタリング習得 • テスト習得 • 複数のプログラミング⾔語を習得 3ヶ⽉ 2年 達⼈プログラマ 中級者からの純粋レベルアップ プログラミング以外も得意 クラウドの普及で最近増加 5年 3年(中級者向けの⾼度なプログラミング知識習得をスキップ) ⼊⾨書完読。 基本レベルの演習を 全て解答可能
  303. 包丁をにぎらず本ばかり読む駆け出し料理⼈ • プログラミングの第⼀歩は本やトレーニングで問題ない • 本だけを読んで「分かった気になる」かもしれないが、実際に コードを書かないとプログラミングは⾝につかない • アプリケーションを作るレベル(脱初⼼者)になるまでは本ト レーニングの演習のようなお題をこなすことで基礎スキルを⾝ につけるのが⼿っ取り早い

    • 同じ演習でもいくつかの解答⽅法はある場合が多いので、いろ いろなテクニックを駆使して解いてみよう
  304. やりたいことは書き始めてから考えよう • プログラミングは作りたいものを作ることで学べる • ただし適切なレベルの作りたいものがある⼈はごく少数 • 多くの個⼈プログラマは以下の3種類を作る • ウェブサービス <-

    おすすめ • デスクトップアプリ • 作業スクリプト • これらの利⽤法を学びながらなにか作りたいものを探すか、練 習がてら⼀般的なサービス(掲⽰板)を簡易模倣したり、仕事の 作業(エクセル操作など)をPythonで実装してみるとよいかも
  305. おすすめ1: Flaskによる簡易ウェブサービスの作成 • Pythonの軽量Webフレームワーク • アクセスされるURLに処理を関数として結びつけることでウェ ブサービスを簡単に作ることができる • ウェブアプリは現在の開発の⼤きな割合になりつつあるので、 簡易ウェブサービスの作成経験は損にはならない

    ページ(HTML)作成の関数1 ページ(HTML)作成の関数2 ページ(HTML)作成の関数3 ページ(HTML)作成の関数4 フレームワーク ウェブサーバー機能 ブラウザ ページ要求 ページを返す 開発者ページ(HTML)作成のみを開発 他のサーバー処理は全てFlaskが担当
  306. 補⾜) HTML/CSS • ウェブページのマークアップ⾔語 • HTMLにウェブページの内容を書く。これをFlaskで動的に作成 する。たとえばお店サイトの商品ページをURLごとに作成 • CSSはHTML(ページ本体)にデザインを加える。 •

    フロントエンジニアやウェブデザイナーなどの専⾨家がいる領 域なので素⼈が有名サイトレベルのものを作ることは不可能 • 素⼈でウェブ作成したければ「Bootstrap」などの「初級者で もそこそこのページ」を作れるフレームワークを学ぶとよい
  307. おすすめ2: Tkinterによるデスクトップアプリの作成 • ⽬に⾒えるものを作るので「プログラム初⼼者が楽しみながら 開発をしやすい」という学習メリットがある • アプリケーションを他の⼈にも利⽤してほしければ「バイナ リ」にしてから配布(⼿法は割愛) • 他にもGUI作成の外部ライブラリがあるので深⼊りするのであ

    れば、Tkinter以外の⾃分にあったライブラリを探すとよい GUIのカウンターアプリ アプリケーションの配布
  308. 補⾜) アプリからのデータベースの利⽤ • 状態を持つアプリケーション(ユーザーや商品などがある)は必ず データベースを使っている • Pythonや他の⾔語およびフレームワークには⼤事な情報を持たせ ずに、データベースを介して情報を読み書きする • フレームワーク依存の⾼度な利⽤法を学ぶまえにローレベルの利

    ⽤法(SQLの直接呼び出し、ORマッピング)を体感しておくとよい Python DB (SQLite3など) Sqlite3モジュール SQLAlchemy
  309. おすすめ3: 業務向けの作業スクリプト作成 • 以下の操作をPythonで実施して省⼒化。ウェブやGUI化してもOK • ディレクトリやファイル操作 • ExcelやCSV • Word

    • PDF • Eメール • 画像 • ウェブページのスクレープ • キーボードとマウス操作の⾃動化 • 英語ですが「Automate the Boring Stuff with Python」のウェブサ イト(無料)がおすすめ。オライリーから4000円ぐらいの邦訳本も でている
  310. 著者が興味でプログラムを書いた例 • 本トレーニングの8章の画像回収ツール相当のものをJavaで作 成(1番最初に作ったアプリ) • ゆっくり実況が好きだったので、⾳声合成ソフトのMacアプリ (Objective-C)とクラウド版(Python + C⾔語)を作成して公開 •

    仕事での巨⼤なログの解析アプリケーション(C++とQt)。あく までも仕事ではなく趣味の⼀環で • 鉱物標本のラベルを作成するサイト • インフラ作業の⾃動化系(趣味から現在の本業へ)
  311. ⼊⾨者卒業に難しい知識はいらない • プログラミングの書籍やウェブ情報は簡単なものから難しいも のまで様々ある • あれもこれもと⼿を出さずに以下に絞って学ぶとよい • 薄い超初⼼者向けのプログラミング書籍を2-3冊を何度も読 む(内容を95%理解するまで) •

    テーマを絞って簡単なアプリを作成する • プログラミングで分からないことは検索をする
  312. 初級者卒業: 美しい設計を体と頭で覚える • このセクションで学ぶこと • スキルは「困ってからの設計変更」で向上 • 複雑さを減らすことに気を配ろう • クラスを徹底活⽤しよう

    • リファクタリング • テスト • デザインパターン • フルスタックフレームワーク: Django • 他のプログラミング⾔語を学んでみよう • 初級者卒業には⾼度な専⾨書が必要 SECTION 02
  313. スキルは「困ってからの設計変更」で向上 • ⾼度なプログラミングスキルの基本は「巨⼤なコードを整理して、 バグを少なく拡張しやすくする」ことに尽きる • ⾼度なプログラミングスキルが役⽴つ場⾯ • 開発前の設計 • 増築/改造を繰り返したコードの整理

    • ⼤規模な開発を効率よくおこなう • 初級者は深い経験が必要なことはできない(短時間では⾝につけに くい)ので、最初からよい設計をするための⼿法を学ぶのではなく、 「とりあえずコードを書きまくり、増築⽅式アプリをでかくしてい き、継ぎ接ぎがカオスになってからコード整理」して体で覚える • どのように設計しなおすと「構造がシンプルになるか」を考える
  314. 複雑さを減らすことに気を配ろう • プログラム複雑になるシナリオ • 関数やメソッドの呼び出しが深くなっている • 1つのデータが⾊々な箇所で読み書きされている • 機能追加をその場しのぎの継ぎ接ぎで加えた •

    複雑なコードを設計変更して綺麗にするとスキルが向上 関数 関数 関数 関数 関数 関数 関数 関数 関数 関数 汚いコード例 (深い階層) 綺麗なコード例 (階層を浅くした)
  315. クラスを徹底活⽤しよう • クラスには様々な機能がある • 処理や複数のデータをまとめられる(トレーニングで学んだ) • クラスにクラスをいれて複雑さをさらに集約できる • 継承により複数の似たクラスの実装をまとめられる •

    多重継承でクラス内のメソッドを分離できる 共通処理のクラス 機 能 機 能 機 能 機 能 機 能 機 能 利⽤したいクラス 常に継承 必要な機能の クラスのみ継承 (ハリボテ) 呼び出し側 多重継承の利⽤例(REST APIをPythonラップするライブラリの作成などに便利)
  316. リファクタリング • プログラム(関数やクラス、モジュールレベルなど)の挙動を変 えずにコードの品質をあげること • 専⾨書籍などで学んでもよいが、初級者は⾃分で試⾏錯誤しな がら設計変更するのがよい(痛いめに合って、それを頑張って解 決することが経験となる) • ライブラリで解決できる問題ではないか

    • 関数、クラス、モジュールの⼤きさは適切か • ループ処理はわかりやすいか • クラスの設計は正しいか • 中級者に近くなったら「教科書的な解答」も学習して覚える
  317. テスト • プログラムが正常に動作するかをテストで確認 • 開発を終えてからテストをするのではなく、モジュールをテス トしながら開発していくことが望ましい • 習得するべきテスト • Printデバッグ

    • ユニットテスト • ツールを使ったテスト(サービスに⼤量の負荷を与えてみる、 Seleniumでブラウザ操作チェックなど)
  318. デザインパターン • ⼤規模なコードを書くための設計パターン • クラスやモジュール間をどう接続して連携するのがよいかとい うベストプラクティス • 1つのシステムから構成される中規模以上のサービス開発で設 計段階で導⼊するとよい •

    ⾃分で設計したりリファクタリングした経験が積み重なってい ないと机上の理論にすぎないので、数年のプログラミングの経 験を積んでから学べばよい(超有名なシングルトンなど10個以 下のパターンをピックアップして学習してもよい)
  319. フルスタックフレームワーク: Django⼊⾨ • メジャーなPythonのフルスタックWebフレームワーク • Ruby⾔語でいうところのRailsに近い • Flaskと異なりウェブサービスに必要なほとんど全ての機能が フレームワークに搭載されているので「フルスタック」と呼ば れる

    • Flaskで作成した動的なウェブサイトの作り込み(DBとの連携や HTML⽣成)あたりをDjangoのモデル(DB)やテンプレート機能 (Jinja)で作り直すとフルスタックのメリットがわかる
  320. 他のプログラミング⾔語の学習 • おすすめはJavaScript。ウェブ開発で他に選択肢がない場合が多い ため • 次点はGo(モダンな開発によい)か、Java(まだ需要が多くてオブ ジェクト指向の学習によい) • 他にはやりたい仕事向きの⾔語(SwiftやC#、PHPなど) •

    以下は3⾔語め以降でよいと思う • Pythonと利⽤⽬的が近い他のスクリプト⾔語(Ruby/Perlなど) • 学習難易度の⾼いC/C++や関数型の⾔語。(これらを必要とする 仕事についていないと利⽤する機会は少ない) • 汎⽤的でない⾔語。Rなど
  321. 初級者卒業には⾼度な専⾨書が必要 • 3000円 - 4000円あたりの書籍は⼊⾨書に⽐べると専⾨的 • 中級者向けの書籍は⼊⾨書よりも扱う範囲が広いので「まんべん なく深い」のではなく「いくつかのトピックが深い」傾向がある • 2000円台の本とは違ってプログラミングの⾼度な専⾨書籍の半分

    以上の知識は必須ではないのですぐには役⽴てられない • 詰め込みではなく継続的に書籍を読み続けてスキルの⼟壌を耕し ておくとよい • コードを書き続けているうちに利⽤するべき場⾯に遭遇する場合 がある。⼟壌が整っていると難しい状況でもよい判断ができる
  322. 中級者卒業: 開発はプログラミング以外にもある • このセクションで学ぶこと • 巨⼈の肩の上に⽴つ凡⼈ > プログラミングだけを知る達⼈ • パーツごとに別々に作成するのが今のトレンド

    • パーツ間の連携⽅法 • 軽量な実⾏基盤であるコンテナ • 既存ミドルウェアをアプリケーションで使う • サービスの監視 • APIフレームワーク: FastAPI • リバースプロキシーのURL設計例 • CI/CDによる省⼒化と安定性の確保 • DevOps環境の構築と著者が採⽤している環境の紹介 SECTION 03
  323. 開発巨⼈の肩の上に⽴つ凡⼈ > プログラミングだけを知る達⼈ • 開発スキルはプログラミングスキル以外も含む • たとえばデータベースの利⽤のように「プログラムに既存のサー ビスを使わせる」ことでシステム開発を効率化できる • 全てをコードで作ると開発も保守も⼤変になる

    Linuxの知識 DBの知識 コンテナの知識 その他、多数 プログラミングスキル プログラミングスキル 開発の達⼈ プログラミングの達⼈ インフラの知識
  324. パーツごとに別々に作成するのが今のトレンド • モノリシックなサービス: 1つの構成要素からなるアプリ • マイクロサービス: 複数の構成要素からなるアプリ • 2010年以降はマイクロサービスが⼤幅に普及 •

    ウェブサービス以外でもマイクロサービスの設計は使える。た とえばプライベート基盤を提供するNutanixの製品もコンポー ネントごとに独⽴したマイクロサービスな設計となっている モジュールC モジュールD (過去遺産) モジュールA モジュールB アプリケーション モノリシックな設計 サービスA (新規でPython製) サービスB (MongoDBなど) サービスC (Go製の過去遺産) サービスD (新規でJava製) APIで連携 マイクロサービスアーキテクチャ 達⼈プログラマ(上級) でないと設計できない 万能プログラマ(上級) でないと設計できない
  325. パーツ間の連携⽅法 • リバースプロキシー: URLによるアクセス先の振り分け。 HTTPSオフロードやキャッシュ機能などもある • メッセージング: サービス間のやりとりのための仕組み(割愛) Web Server

    API Server Image Server /api/...へのアクセス /images/...へのアクセス /...へのアクセス リバースプロキシー 内部IPで通信 外部IP(1つ) アプリケーション全体 サービスA サービスB サービスC
  326. 軽量な実⾏基盤であるコンテナ • コンテナはサービスを独⽴させるのに便利なツール • 軽量ですぐに起動できて、どこでも動かせる擬似OS環境 • 複数のコンテナを1つのホスト上で動かしたり、多数のコンテ ナを複数ホストで構成されるクラスタ上で動かせる 本番ホスト Docker

    コン テナ コン テナ コン テナ コン テナ コン テナ コン テナ コン テナ コン テナ ホスト1 Docker ホスト2 Docker クラスタ(Kubernetesなど) コン テナ コン テナ コン テナ コン テナ コン テナ コン テナ コン テナ コン テナ コン テナ コン テナ コン テナ コン テナ コン テナ コン テナ コン テナ コン テナ 開発ホスト Docker コン テナ コン テナ コン テナ コン テナ コン テナ コン テナ コン テナ コン テナ コン テナ 他環境(別IPなど)に すぐに移せる マイクロサービスの各サービスを コンテナとして動かすことが多い
  327. 既存ミドルウェアをアプリケーションで使う • 以下は筆者がマイクロサービス開発よく使うサービス。⾃作す るのではなくサービスを使う前提でプログラムを書くと簡単 • NGINX • リバースプロキシー • ウェブサーバー(静的なファイルの配布)

    • MongoDB: ドキュメント指向データベース。プログラムが使う データ構造(辞書型。JSON)をそのまま格納したり検索可能 • Redis: KVSと呼ばれる⾼速なキャッシュ • オブジェクトストレージ: ファイルやイメージをURL形式で保 存する。著者はローカルではMinioを利⽤
  328. サービスの監視 • 複雑に構成されるサービス群は監視が必要。以下は著者の構成 • Loki: システムログの集約(次世代のシスログサーバー) • Prometheus: メトリックの集約(性能や稼働状況などの指標) •

    AlertManager: しきい値を超えた際に管理者にメール通知 • Grafana: 集約したログやメトリックを表⽰、検索 ホスト Docker (Loki Logging Driver) コン テナ コン テナ コン テナ コン テナ コン テナ コン テナ コン テナ コン テナ 全コンテナの ログ 全コンテナの メトリック ウェブで表⽰
  329. ミドルウェアを利⽤する際のポイント • 完璧なものを⽬指すのではなく規模にあったコスパで選ぶ • 「構築/運⽤コストと覚えること」は少ないほうがいい • たとえば著者はログ監視にElasticsearch/Kibana/Fluentdという 構成ではなく、Grafanaを使っているのでLokiを採⽤している • 状態をホストやコンテナではなく共有されるミドルウェアに任せる

    • たとえばローカルキャッシュではなくRedisを使う • たとえば画像やファイルの管理はローカルではなくオブジェクト ストレージを利⽤する • これを守らないとパーツへの依存性が発⽣して、構成変更(ノード 数を増やすなど)の難易度が跳ね上がる
  330. マイクロサービスのウェブアプリの構成例 Node (SPA担当) ウェブサーバー (静的ファイル配信) Node (JS等のビルド) APIサーバー 1 APIサーバー

    N Minio(画像) JS CSS 画像 gulp アプリサーバー (HTML⽣成) 内部API呼び出し 画像の 取得/保存 画像取得 外部API呼び出し SPAのページへの アクセス 静的ファイル 取得 ページ アクセス Redis MongoDB キャッシュ セッション管理 データ管理 Grafana Loki Prometheus Exporters 管理/監視系 AlertManager Browser ページ アクセス セッション管理 (ログイン状態で表⽰切り替え) JavaScript API呼び出し リバースプロキシ + ⼀部のキャッシュ 信頼できないゾーン 信頼できるゾーン コンテンツビルダー (MarkDown -> JSON) ページデータ 作成 ... ⾃作ツール群
  331. APIフレームワーク: FastAPI⼊⾨ • フルスタックフレームワークはマイクロサービス向きでない • Flaskのような軽量フレームワークを主体とした⼩型のAPIサー バー群を⽤途ごとに作成する • 著者はPython製のAPI向けで⾼速なFastAPIを利⽤している Docker

    (Logging-Driver) ミドルウェア • 例外処理 • Prometheus Exporter APIの実装 他のAPIサーバー Appサーバーのみ他を参照 Redis MongoDB キャッシュ セッション管理 データ管理 バルクアクセス Prometheus Loki APIアクセス
  332. リバースプロキシーのURL設計例 • リバースプロキシーでプレフィックス(前⽅)基準でURLごとに処理変更 • ウェブ(APPサーバー)の懸念事項 • キャッシュ対象(全ユーザー共通)と⾮対象(ユーザーごと)ページがある • 同⼀ドメインで多⾔語対応させることが現在は多い(URLで⾔語区別) •

    APIの懸念事項 • 複数のAPIサーバーが存在している。APIのバージョン管理も必要 • パブリックAPI(外から)とプライベートAPI(中のみ)がある • URLの設計例 • 静的ファイル: /static/... • ウェブ: /<キャッシュの有無>/<⾔語>/... • API: /api/<public/private>/<api名>/<バージョン>/... • オブジェクトストレージ: /images/...
  333. CI/CDによる省⼒化と安定性の確保 • リポジトリにコードをPushしたら複雑なマイクロサービスアプ リを全⾃動でビルド。⼈間よりスクリプトのほうが信頼できる • ビルドしたコード(イメージ)を起動して全⾃動でテストを実施 • テストにパスしたらステージング環境にのせて、管理者が最終 チェックしてから本番環境に切り替える 著者が採⽤しているDockerアプリの

    CI/CDの流れ。 Kubernetes利⽤時はDocker-Composeでは なく実際にK8sを利⽤する。 宣伝!! 詳しくは私のDocker本にあります
  334. DevOps環境の構築 • DevOpsはバズワード • DevOpsの著者なりの解釈は「CI/CDを中⼼として、(クラウド より上の世界での)インフラを維持しつつサービスを開発/更新 公開し続ける技術」 • ⼩規模なDevOps環境はある程度の知識と試⾏錯誤は必要だが、 個⼈レベルで構築可能

    • 上級者向けの個々の技術を1つ1つ深堀りする前に、とりあえず 全体像を理解するために浅知恵でよいので作って動かすべき • 開発と運⽤にDevOpsを採⽤するのであれば、チームの半分以 上は全体像を掴んでいること • 少数精鋭チームから導⼊して横展開することを推奨
  335. 著者が採⽤しているDocker中⼼のDevOps環境 Dockerレベルの運⽤ Compose (開発サーバー) Dockerfile DockerHub (Pull) Compose (本番環境) Compose

    App Infra Ansible ホストレベルの運⽤ Python GitHub (Code Push) App Infra App Compose (⾃分のPC) GitHub (Code Pull) Dockerfile Jenkins (ビルドからデプロイまで) DockerHub (Push) Jenkinsのトリガー GitHub (ドキュメント等) メトリックとログ 規模が⼤きくなると ビルドからデプロイは Composeではなく Kubernetesに切り替え
  336. 駆け出し編: インフラエンジニアという道 • このセクションで学ぶこと • ウェブ業界はレッドオーシャン • ITインフラ業界は敷居が⾼いが安定している • 代表的なインフラエンジニアの仕事

    • 本当の基盤(電気、空調、ラック) • ネットワーク系 • サーバーとストレージの世界 • パブリッククラウドとプライベートクラウド • 構成管理ツール • インフラの⾃動化 • 専⾨性や資格について SECTION 04
  337. ウェブ業界はレッドオーシャン • 低スキルから中堅まで⼈材が豊富 • ⾒た⽬にわかりやすい仕事なので新⼈が多い • ⼤量のプログラミングスクール卒業⽣ • ⼀部の優秀なエンジニアや好業績の会社を除けば、求められる 技量のわりに待遇がITインフラ業界より低いことが多い

    • 技術のサイクルが速いのでずっと(⼤量に)勉強し続けないとい けない
  338. ITインフラ業界は敷居が⾼いが安定している • 専⾨知識が要求されるため学習が必要 • ウェブ業界に⽐べると⼈員供給が少ないので需要が多め(?) • ウェブ業界に⽐べるとコア技術の変遷が⼩さい(ウェブ開発スタ イルは⼤きく変わっても、ネットワークの仕組みやLinuxの根 幹は簡単には変わらない) •

    以後で著者が経験したインフラエンジニアとしての仕事内容を 列挙していく • 仕事が⾯⽩そうと感じたなら、ウェブ屋よりもインフラ屋を駆 け出しエンジニアは⽬指したほうが仕事と給料は安定する可能 性が⾼いかも
  339. サーバーラック利⽤法の設計 • コアとなるIT機器はサーバーラックに搭載するのが⼀般的 • インフラエンジニア以外がこれらを⾒かけることは珍しい • サーバーラックの利⽤法の設計に必要なステップ 1. ネットワークとサーバーの論理設計 ->

    物理設計 2. 必要な電⼒と発⽣する熱量の設計 3. 物理⼯事(ラック設置、電⼒供給、ACの設置) • 配線が多い場合はネットワーク機器をToR(Top of Rack)ではな くMoR(Middle of Rack)にするとケーブルを分散させやすい。 必ずケーブルガイドを使って配線を左右に逃がすこと • スイッチのポート(ケーブルがささる側)はラックサーバーにさ すものは背⾯側の機種を選ぶ。それ以外は前⾯側にする
  340. サーバーラック利⽤法の設計例 ... 1G L2 Switch 1G L2 Switch 2U/4Node Servers

    2U/4Node Servers ... 2U/4Node Servers 2U/4Node Servers ... Core L3 Switch Core L3 Switch Data Stack Data Stack ... Voice Stack (PoE) Voice Stack (PoE) ... ... Infra Servers 10G/40G L3 Switch 10G/40G L3 Switch 1G L2 Switch 1G L2 Switch 2U/4Node Servers 2U/4Node Servers ... 2U/4Node Servers 2U/4Node Servers ... Firewall Firewall ONU ONU Career1 Career2 Internet Wifi Stack (PoE) Wifi Stack (PoE) Wifi Controller Wifi Controller PCs on Desk IP Phones on Desk Meeting Systems APs 終端ラック(1,2): ラック間の接続その他 ラック(1-N): ワークロード⽤ 10G/40G L3 Switch 10G/40G L3 Switch バックボーン接続(冗⻑化) ラック内接続(冗⻑化) ラック内接続(冗⻑化) ラック内接続(冗⻑化) 床下配線 冗⻑化 オフィスエリア 天井配線
  341. 電⼒と空調の設計 • IT基盤を動かすより低いレイヤーの基盤 • 電⼒: サーバーは200kVAでのPSU冗⻑化が⼀般的(kVA≒KW) • ラックあたりの電⼒量: ⼀般的には4kVA -

    20kVA程度 • 重要な環境は電気系統と空調も冗⻑化すること • コールドアイル(冷たい空気)の通路をラック前⾯に設置し、 ホットアイル(排熱による暖かい空気)をラック背⾯に設置 • 排出熱量に猶予をもたせること。空調が冷やせる限度を越える と冷⾵が送れずに急激にオーバーヒートをおこす。夏は室外機 (排熱)も⾼温になるので冷却性能が落ちる点に注意 • ITインフラとは異なる領域なので、その専⾨家(電気、空調等) と相談しながら要件にあった設計をする(⼿伝う)必要がある
  342. 電⼒と空調の設計例 Front Front コールド アイル 室内機 室外機 室外機 室内機 ホット

    アイル 発⽣する熱量と電気使⽤量、価格 あたりから適切な機器を選定する。 弱いよりは強いほうがだいぶマシ。 稼働後の増強は難しい(⾦と時間がかかる) 排熱環境に注意 排熱できない = 冷やせない 200V 100V 200V 100V 200V 100V 200V 100V 200Vの電⼒使⽤量の⾒積もりが必要。 100Vを⼤量に使⽤する場合は⼤容量の 配電が可能な200Vを使うことを検討。 ⽇本では100Vもないと不便 100V配電盤 200V配電盤 ... PDU(電源タップ)は 背⾯側の左右が基本
  343. L2/L3ネットワークの設計 • L2ネットワーク: 同じネットワーク内の通信 • L3ネットワーク: ネットワーク間をまたぐ通信 • L3スイッチ: ネットワークの中⼼なる機器。L2/L3の両対応

    • 設計のコツ: 利⽤⽤途から正しいサイジングをして、L2の物理 範囲を狭めて、アドレス集約を徹底してルーティングを簡単に する。責任分界点には社内であってもFirewallを設置する • 重要箇所は全て冗⻑化することが必須 • ネットワークを使う側のサーバーエンジニアのレベルは⾊々 • ネットワークに詳しくない⼈が使う⼤きなVLAN(Native) • 詳しい⼈が複雑なことをできる複数の⼩さなVLAN • パブリックIPやDMZの設定は素⼈にはやらせないかガイド
  344. L2/L3ネットワークの設計例 Goto Corp, External Office 10.4.0.0/16 Office Core Office Infra

    Office Data 1 Office Voice 1 Office Wifi 1 External Firewall VRF Routing + Internal Firewall Goto Corp, External Site B Small Sites Big VLAN Small VLANs Site A External Firewall Lab1 10.5.0.0/16 Lab2 10.6.0.0/16 10.4.0.0/23 10.4.100.0/24 10.4.101.0/24 10.4.2.0/23 10.4.4.0/22 10.4.8.0/22 10.4.12.0/22 10.5.0.0/17 10.5.128.0/20 ⽀社A 10.4.0.0/14 本社: 10.0.0.0/8 (全⽀社は内部にある) ... ⽀社B ⽀社C ... サイト間VPN(冗⻑化) サイト間VPN(冗⻑化) サイト間VPN(冗⻑化) 必要に応じて 拠点間も直接 接続をする 極論すると全てスタティックルートの設定で まかなえるぐらい経路を集約しまくること。 最初に正しく設計してないと集約できなくなる Internet 10.0.0.0/8 10.4.0.0/14 0.0.0.0/0 Corp 0.0.0.0/0 10.6.0.0/16 全ての通信を 通す必要はない
  345. 名前解決の設計 • ドメイン名をIPアドレスに変換する仕組み • アプリケーションを様々な環境で動かすための必須条件なので、 クラウドが⼀般化した今では昔よりも重きがおかれる • 完全にランダム割り振られるDHCPや固定IPの使⽤ではなく、 「IPAM(IP Address

    Management)」で賢くDHCPを使うこと • クラウドにはIPAMが搭載されることが多い • 存在しない場合には作る(Linux or Windows) • アプリケーションを構成するノード間は名前解決で連携できる ように実装しておくこと。接続先を固定IPではなく解決可能な ドメイン名にしておく。⾃分⾃⾝のIPもDHCPでIPAMから得る
  346. 名前解決の設計例 プライベート クラウド パブリック クラウド コンテナ基盤 VLAN 172.30.0.0/16 VPC 172.31.0.0/16

    コンテナネットワーク 172.32.0.0/16 Backend VM Front VM Reverse Proxy etc Backend Instance Front Instance CDN etc Backend Container Front Container Load Balance r etc IPAM + DHCP(管理コンソール) IPAM + DHCP(管理コンソール) YAMLでの定義 ネットワークアドレスに依存せずサービス 構成ノード間で会話できる必要がある。 IPではなく名前で相⼿を指定する。 フロントも直接外に出さないほうがよい Global IP DNS 公開⽤パブリックIPとサービスのドメイン名の結びつけ
  347. Wifiの設計 • 物理設計 • L2ネットワークへの接続と給電(PoEが多い) • アクセスポイントがカバーできる範囲の調査 • 設置ポイントと⼈⼯密度、衝突しない周波数の調整など •

    認証システム • 物理的に離れた多数のAPをどう⼀元管理するか • 数⼗台以上のAPは個別ではなくコントローラーに設定を集 約するのが基本
  348. セキュリティの設計 • Firewall • 社外から社内だけでなく、社内から社外への通信も対象 • 社内の異なるグループ間もFirewallを通すべき • VPN •

    サイト間接続 • PCからの接続 • ActiveDirectory(AD) • セキュリティ系の機能はADに強く依存しているものが多い。 また、ADを安定稼働させるための専⾨知識が必要 • FirewallやActiveDirectoryも壊れることがあるので、冗⻑化と 壊れた際にきちんとシステムが動き続けるかの検証が必須
  349. クラウド間接続の設計 • 接続⽅式 • VPN • 専⽤線(ダイレクトコネクト): ⾼額 • アドレスレンジを「/16」程度で分離しておかないとルーティ

    ングができなくなる(パブリッククラウドには従来のL2/L3の ルールが適⽤されないことが多いので注意) • アプリのレイヤーを「グループレベルでクラウド間で動く」こ とを前提に構築しておく必要がある。クラウド間やリージョン 間は遅延が⼤きいので「アプリはクラウドでDBはオンプレ」 などの構成はNG
  350. クラウド間接続の設計例 172.31.0.0/16 Public Cloud (AWS) 172.30.0.0/16 Public Cloud (Azure) 172.31.1.0/24

    172.31.2.0/24 172.31.3.0/24 VM VM VM VM VM 172.30.1.0/24 172.30.2.0/24 172.30.3.0/24 VM VM VM VM VM Firewall Appliance 1 Firewall Appliance 2 L3 Switch (Gateway) 172.16.0.0/16 Private Cloud (Nutanix) 172.16.1.0/24 172.16.2.0/24 172.16.3.0/24 VM VM VM VM VM VPN VPN 0.0.0.0/0 via L3 Switch 172.31.0.0/16 via L3 FW1 172.30.0.0/16 via L3 FW2 172.16.0.0/16 via L3 Switch 172.31.0.0/16 via AWS 172.16.0.0/16 via FW1 172.30.0.0/16 via Azure 172.16.0.0/16 via FW2 VLAN X VLAN Y ⽮印の通信経路の設定はスタティック ルートか⾃動学習(BGPとOSPFなど)で与える
  351. 物理サーバーの設計 • 今は「仮想化」を前提に考える。ベアメタルは特殊な状況のみ • 基盤導⼊後に拡張することを前提に考えておく(ネットワークのア ドレス空間の⼤きさ、物理スペース、電⼒、エンジニアの物理と 設定作業のコストなど) • ミドルレンジより性能が上がっても落ちても「処理能⼒あたりの 購⼊価格」が⾼く傾向、台数が増えると維持コストが増える

    • 物理より上の価格(ライセンス代など)が⾼ければ、⾼いサーバーで コストを圧縮したほうがよい。普通はコスパでミドルレンジを選 び、予算がなければローエンドを選ぶ。ミッションクリティカル 環境はハイエンド • ワークロード(負荷)に応じたサイジング(台数や構成決定)をする
  352. 物理サーバーの設計例 ハイパー バイザー ハイパー バイザー 仮想化基盤のクラスタ 物理サーバー 物理サーバー SAN Switch

    San Switch Network Switch Network Switch 上流 ネットワーク ストレージ ストレージ VM VM VM VM VM VM VM VM VM VM VM VM VM VM ... 上流 ネットワーク 物理サーバー 物理サーバー Network Switch Network Switch プライベートクラウド VM VM VM VM VM VM マネージドDB その他機能 レガシーな「3Tier」と呼ばれる構成 構築と拡張が難しい 現在主流になりつつあるプライベートクラウド⽅式 全般的に3Tierよりも簡単(個⼈で作る⼈もいるぐらい) ... コン テナ コン テナ コン テナ コン テナ
  353. 障害と保守 • 機械は壊れるもの • ソフトウェアにはバグがある • エンジニアは知らないことが多いし間違えることも多い • アプリでバグがおきるようにインフラにも障害が発⽣する •

    障害に対応するように以下が必要 • ハードウェアの冗⻑化(2つ構成で組み、1つ壊れても動き続 ける) • 冗⻑化と故障を想定した設計のソフトウェア • 障害発⽣時の対処法(知識かマニュアル) • 保守契約(ハード交換や障害復旧の⼿伝い) • ハードやソフトに詳しくなりたいならきちんとした保守(技術サ ポート)の仕事から始めるとよいかも。著者も経験者
  354. ストレージの設計 • ⼤前提として以下の3種類を区別する • サーバー内のSSD。⾼速だが死ぬと終わるし融通が利かない • NAS(共有ファイルサーバー, NFS/SMB) • 外部ブロックストレージ(SCSI,

    iSCSI) • サーバー冗⻑化には外部ストレージが必要なことが多い • SCSI(SAN)は⼤企業向けだが、iSCSIは⼩規模向け • 環境の引っ越しをしにくくなる第⼀要因はストレージ(DB含む) なので最初から移⾏プランを考えておくのがよい • ストレージとSANの障害はインフラ障害で最もダメージが⼤き いのでデリケートな箇所。基盤のパフォーマンスのボトルネッ クにもなりがち。バックアップ必須 • ストレージとSANのエンジニアは⽐較的レアキャラ
  355. データベースの設計 • 2種類のDBエンジニア • アプリより: アプリが使いやすいテーブルの設計 • インフラより: 複雑なクエリーや、冗⻑化やバックアップ •

    純粋な「データベースだけをやるエンジニア」は少ないのでア プリであれば開発(アプリ側がDBをどう使うか)を先に学び、イ ンフラであればDBが動くサーバーレベルを先に習得するのが 個⼈的推奨 • SQL⾃体に詳しくなる(知っていてあたりまえ)というより、運 ⽤(クローンやバックアップ、スケールアップ)周りの知識が特 に求められる • DBの障害(システム全停⽌)でもデータは絶対になくさないこと
  356. バックアップの設計 • 冗⻑化(Raidなど)はバックアップではない • 仮想化のスナップショットもバックアップではない • 集約箇所やシステムごとなくなる可能性を考慮しておくこと • バックアップのレベル •

    ファイルレベル(以下のどれかの付属機能なことが多い) • OSレベル • 仮想環境レベル • ストレージレベル • バックアップ取得時間とバックアップからの復旧時間もだいじ な指標なので、検証環境で実測しておくこと(バックアップはあ るけど戻しに2⽇かかります。などということも。。。)
  357. パブリッククラウドの設計 • 「とりあえずOSを使いたい」という状況でインフラの構築と運 ⽤が不要で簡単に使えるというメリットがある • 動かすサービスをクラウドに適した設計に変更し、インスタン スを使い捨て(スケール含む)にできることが望ましい • マネージドサービスを使うことで「DBなどの⼿がかかるマシ ンのおもり」をへらすことができる

    • インターネットに近いのでウェブサービスに強い • 「従来の業務⽤VMを24時間稼働させる」⽬的でパブリックク ラウドを使うと割⾼になることが多いので注意が必要 • 注意:「特定パブリッククラウドのシステムにだけ強い」という エンジニアは⻑期的には不安定だと思われる。クラウドにも役 ⽴つベーシックなLinuxと開発スキルにも投資すべきかも
  358. パブリッククラウドの設計例 パブリッククラウド基盤 インスタンス (ウェブサーバー) マネージドDB インスタンス (アプリサーバー) バックアップ インスタンス (アプリサーバー)

    インスタンス (ウェブサーバー) CDN(Cache) + HTTPS Offload ドメイン名 RDS S3 EC2 Cloud Front Route53 インターネット ユーザー 名前解決 アクセス サービス名にはAWSを使ったが、基本機能程度の利⽤であれば 主要クラウドであれば似たサービスを持っている。 これ以外にもサーバーレスや各クラウド独特の機能は多い。 初⼼者は汎⽤(どのクラウドでも使える)機能から学ぼう プライベートネットワーク 広いエリアからの⼤量のアクセスに 強いが、特定の拠点(会社など)からの ⼤量のアクセスには弱い。 ⾃社ファイルサーバーなどはクラウド ではなく拠点内に置くのが⼀般的。
  359. プライベートクラウドの設計 • パブリッククラウド相当のものを社内に構築する • レガシーな3Tier構成やOpenStack(難しいので専任エンジニア が多数必要)より、NutanixのHCIなどの構築と運⽤が簡単なも のがよい • 展開する台数が多い場合は仮想マシン(インスタンス)単価で考 えると、パブリッククラウドより安価な傾向(1/2

    - 2/3程度) • 初期投資が必要なので⼩規模な場合はパブリッククラウドより も⾼額になる傾向 • 24時間稼働のエンタープライズアプリや、⾼トラフィックが必 要なVDI、⾃由な操作が求められる開発基盤などに適している • 注意: プライベートクラウドはパブリッククラウドに⽐べると 設計と運⽤がきちんとできるインフラエンジニアが必要
  360. プライベートクラウドの設計例 物理基盤(電気、ネットワーク) VM VM VM VM VM VM VM VM

    VM VM VM VM VM VM VM VM VDIサービス (管理された⼤量のユーザーマシン) ⼤量の社内通信 (40G以上の⾼速なLAN) ⾃社設備(オフィス、データセンター) VM VM VM エンタープライズ アプリケーション (会社の重要システム) DB バック アップ プライベートクラウド基盤 ⼤量のユーザー(社員) 社内通信 秘匿データ VM VM VM VM インターネット Firewall セキュリティ管理 Firewall セキュリティ管理 VPN 社外の ユーザー (社員)
  361. 構成管理ツール • 主にサーバーレベルでのインフラ構築/変更作業は「構成管理 ツール(Ansibleなど)」を使うことで省⼒化できる • 定義した構成にサーバーを⾃動設定(初期構築/変更)してくれる サーバーA サーバーB サーバーC 構成ファイル

    (Yamlで定義) Ansibleを実⾏ Ansibleが⾃動設定 必ず構成管理ツールで 全ての設定をしないと いけないわけではない 著者の利⽤例 • 構成管理ツール: Dockerホスト やK8s環境の構築(⼟台) • コンテナ: アプリケーションの 構築
  362. インフラの⾃動化(1) • ITインフラの仕事には定型業務が多い • 新規ネットワークを作成した際の機器の設定変更 • 仮想マシンを作成する際の設定作業 • マシンやログの監視とアラートの作成 •

    決まりきったことを毎回⼈間がやるのではなくプログラムに実 ⾏させることで労⼒削減ができる • 定形作業(⼿続きの流れが明確)以外は⾃動化できない • システム開発には「開発とインフラの両⽅の知識」が必要 ⼈海戦術の廃⽌ プログラム ITインフラ 操作省⼒化 ⾃動実⾏(定期/イベント駆動)
  363. インフラの⾃動化(2) • 管理者が増えると作業が遅くなる。マシン展開の例 1. ネットワークエンジニアが場所とアドレスを決める 2. セキュリティエンジニアがポリシーを設定 3. サーバーエンジニアがインスタンスを作成 4.

    アプリエンジニアが環境をもらえる 5. 監視員がリソース利⽤状況をチェックして使いすぎを警戒 • ⾃動化された例。インスタンス構成のプラン化と⾃動作成 1. アプリエンジニアが必要なインスタンスの種類を選ぶ 2. システムが機械的にインスタンスを作成 3. アプリエンジニアが環境をもらえる 4. システムがクオーターを超えた利⽤やアイドルを検知した らユーザーと管理者に通達
  364. インフラの⾃動化の構築例 VM VM VM VM 基盤構築アプライアンス クラウド基盤 (Nutanix) Foundation VMs

    基盤のイメージング 物理ネットワーク設定 基盤の初期設定 (論理ネットワーク等) 仮想マシン管理 (クラウドレベル) 仮想マシン設定 (OSレベル。Ansible) Nginx(Reverse Proxy) + Node(SPA) DB (基盤情報) 物理電源操作 (Power-on/off) ベアメタルサーバーへの クラウド基盤インストール REST API IPMI, SSH SSH, Ansible REST API ⾃動化の利⽤者 L3物理 Switch 物理ネットワークの結線 マイクロサービス設計の ブラウザアプリ SSH, API SSHにはPythonのParamikoを利⽤ するのがおすすめ。 ローカルコマンドと同じ感覚で リモートでのコマンド発⾏が可能 ブラウザGUI 仮想マシンレベル の⾃動化 基盤レベル の⾃動化 ネットワークレベル の⾃動化 Docker (VM設定後)
  365. インフラのおかね • 買う価格: 物理機器やライセンスなどのコスト。性能と安定性及び 価格を考慮して構成を決める • 維持する価格: 買った後に維持するコスト。⼈件費や保守費。複雑 なシステムだと⾼くなる •

    「常に⾼機能/⾼性能であればいいわけではない」ことに注意。た とえば画像編集の素⼈は⾼いお⾦を払ってPhotoshopを買うよりも 安いiPhoneアプリのほうがうまく使えるのと同じ。必要になって からPhotoshopを買えばいい。必要な機能を⾒極めて「可能な限り シンプルなものを選ぶ」ことを⼼がける • オープンソース vs ベンダー製品: オープンソースは素晴らしいが、 それを採⽤することによる「構築コスト、運⽤コストの増加、サ ポートを得ることが難しい」点を懸念すること。全てのオープン ソースが著名なオープンソース相当のレベルと思わないこと
  366. 開発やインフラの専⾨性を変えることについて • キャリア的に袋⼩路に陥ったと思ったら「今の⾃分が得意なこと」 から「半歩だけ外(完全に別領域ではない)」に出てみる • 著者の場合はデータセンターというカテゴリで「ネットワークエン ジニア(4年) -> サーバー仮想化エンジニア(4年)」とキャリアチェン ジし、クラウドという観点で「インフラエンジニア(合計8年)

    -> DevOpsエンジニア(現在1年め)」とキャリアチェンジしている • 正しいタイミングで正しい場所に移れるように⾃分が関わるIT技術 全般についてはエキスパートレベルではなくとも「素⼈ではない」 状態にしておくのが⼤事 • 指標として業界の最⾼峰と呼ばれる⼈達と会話して「なんか違う な」「⾃分のほうができる(たいていは勘違い)」と感じたら少し別 の領域へ移ることも検討する
  367. IT系の資格について • IT資格は特定領域を包括的に勉強するには役⽴つ(投資的価値) • 資格を取るだけでは本当のエキスパートにはなれない。たとえば 著者が社会⼈4年⽬のときに「Cisco CCIE」「RedHat RHCE」 「VMWare VCAP」「Oracle

    Java Gold」と広いエリアの⾼ランク の資格を持っていた。知識はあったが技術⼒評価では社内の最下 位職位の下位20%程度。知識と技術⼒は別ものと割り切ること • 戦略的に適切なタイミングで転職やポジションの変更をおこなう ことで机上の知識を現場スキルに落とし込める • 英語ができると国内でもキャリアの選択肢が増えて、ライバルが ⼤幅に減るので、個⼈的には既にプロ以上のレベルの⼈はIT系より も英語の勉強のコスパのほうがはよいかもしれないと思う
  368. 歴史編: 開発とインフラの技術変遷 • このセクションで学ぶこと • おおまかなインフラの歴史 • おおまかな開発の歴史 • ペット

    vs 家畜 • クラウドの抽象化 • トレンドを読むことで将来に備える • 終わりに SECTION 05
  369. おおまかなインフラ基盤の歴史 • - 2005ベアメタル • 全OSを直接ハードにインストール • 2000 - :

    サーバー仮想化(3Tier) • ハード上のハイパーバイザーに複数のOSをインストール • 2010年までは主流だったが構築と維持コストが低いパブリック/プラ イベートクラウドに置き換えられることが現在は多い • 2010 - : パブリッククラウド • 開放されているコンピュート資源をお⾦を払って借りる • ⾃分で構築しないのでメンテナンスコストが下がる • 2015 - : プライベートクラウド • 構築と維持が難しいサーバー仮想化を簡単に実現できる • パブリッククラウド相当のものを⾃組織のために構築する • 2020 - : ハイブリットクラウド • 複数のパブリッククラウドとプライベートクラウドのミックス構成
  370. おおまかなインフラ基盤の歴史(図) HW HW HW OS OS OS HW HW HW

    OS サーバー仮想化 ストレージ OS OS OS OS OS OS OS HW HW HW OS OS OS OS Managed Services SAN HW HW HW OS OS OS OS Managed Services ベアメタル 2000 ~ 2010 ~ 2015 ~ 2020 ~ サーバー仮想化 クラウド 2020 ~ パブリック プライベート ハイブリット OS OS OS OS HW HW HW OS OS OS ハイブリット 2020 ~ ハイブリット
  371. おおまかな開発⼿法の歴史 • - 2000: 開発の対象はデスクトップアプリ中⼼ • Javaによるエンタープライズ向けサービスの開発など • 2000 -

    2010: サーバーサイドレンダリングのウェブサービス開発 • Windows95/98あたりからPCとインターネットが⼀般に普及 • ⼀般ユーザー向けのサービスがブラウザ経由で提供されはじめる • 2005 - : クライアントサイドレンダリングのウェブサービス開発 • ページ遷移を伴わずにページ内容を書き換えるブラウザアプリ • Google Mapなどが広く普及し始める。多くはサーバーサイドレンダリ ングとの併⽤ • 2010 : ⾼速な開発/更新とスケールするウェブサービスの開発 • インターネット上のユーザー数が膨⼤な数となる • ユーザーを集めるために⾼速にサービスを開発/公開を繰り返して、⼤ 量のトラフィックを捌ける設計が採⽤されるようになる • スマホやタブレット向けアプリも⼤きく普及
  372. おおまかな開発⼿法の歴史(図) ビジネス アプリケーション サーバーサイド ウェブアプリ クライアントサイド ウェブアプリ スマホ向けアプリ 複雑化した ⼤規模ウェブアプリ

    2000 ~ 2005 ~ 2010 ~
  373. ペット vs 家畜 • インフラと開発に共通するトレンド。ペットのような環境から家畜のよう な環境へ。 • ペット • ⾮常に⼤事な存在なので、⼿がかかる

    • 数は少ない • 病気になったり死んだりするとダメージが⼤きい • 家畜 • 機械的に管理される存在 • 数は多い • ごく⼀部が病気になったり死んだりしても、ダメージは⼩さい • クラウドで「家畜のように扱えるサービスを開発」することで、インフラ 側の構築/運⽤コストを⼤幅に減らせる
  374. HW HW OS サーバー仮想化 OS HW HW OS OS クラウド

    HW HW HW HW クラウド OS OS OS Managed Network Managed Storage Managed Database マネージドサービス • マシン台数の削減 • 複雑な操作を削減 コンテナ サービス開発⼒ 維持管理 変更コスト OS OS OS OS Legacy Backup etc. Legacy Backup etc. VS レガシーな開発と運⽤⽅式 新しい開発と運⽤⽅式 ビジネススピード ペット vs 家畜 (図)
  375. クラウドの抽象化 • 変化が激しい世界ではサービス(⼀般向け、社内向け)を塩漬け させないことが⼤事 • 塩漬けさせないコツ • 「開発して終わり -> 2年後に更新」ではなく運⽤を続けな

    がら開発を継続する • 開発したサービスをすぐに「どこにでも」展開できる • 特定クラウドにサービスを依存させないコツ • 特定クラウドに特化した機能ではなく、汎⽤的な機能を使う • コンテナやオーケストレーションツールをつかって、サービ ス⾃⾝を最初から可搬性が⾼い設計で作る
  376. クラウドの抽象化 (図) HW HW HW HW HW HW パブリック1 プライベート

    HW HW HW パブリック2 Ct2 Ct1 クラウドの抽象化レイヤー(Docker, Kubernetesなど) Ct2 Ct1 開発 本番(ウェブサービス) Ct4 Ct3 開発 Ct4 Ct3 Ct4 Ct4 本番(ビッグデータ処理)
  377. トレンドを読むことで将来に備える • ⾰新的な技術はいきなりは普及しない • その技術が求められている⼟壌が確実にある • 技術が誕⽣してから最先端の⼈達に広がるのに3年以上はか かる。⼀般層に広がるにはもっと時間がかかる • ⽇本で普及する前にアメリカで普及することがほとんど

    • 相当な審美眼がない限りは超最先端を追う必要はなく、超最先 端な技術の多くは普及せず終わる • 「世間に広まりつつあるな」と思ってから「誰にたいして」 「背景」「タイミング」などについて考察してみる • 興味を持てば新しいことは楽しんで学べるし試せる
  378. 終わりに • ⼩中学校でのプログラミング履修からわかるように、簡単なプ ログラミングは⾮ITを含む多くの業務で求められるベーシック スキルとなりつつあります • Pythonは他の多くのプログラミング⾔語より簡単で、いろいろ な⽬的で利⽤することのできる⾔語です • 是⾮、本トレーニング資料を読んで終わりにするのではなく実

    際に⾃分の⼿でプログラムを書いてみてください