Python 文法まとめ

### 目次

<a href="https://colab.research.google.com/github/kiryu-3/Prmn2023/blob/main/Python/2024/Systax/PythonBasic.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a>


1. **[プログラミング入門](#1-プログラミング入門)**
   - [1.1 プログラミングとは](#11-プログラミングとは)
   - [1.2 Pythonとは](#12-pythonとは)
     - [WEBアプリケーション開発](#webアプリケーション開発)
     - [データ分析](#データ分析)
     - [機械学習・AI](#機械学習ai)
     - [ゲーム（GUI）アプリ開発](#ゲームguiアプリ開発)
     - [スクレイピング](#スクレイピング)
   - [1.3 プログラミングの進め方](#13-プログラミングの進め方)
   - [1.4 print関数](#14-print関数)
   - [1.5 コメント](#15-コメント)
   - [1.6 エラーへの対処方法](#16-エラーへの対処方法)
   - [1.7 Pythonプログラミングにおける注意](#17-pythonプログラミングにおける注意)
2. **[Python文法(基礎)](#2-python文法基礎)**
   - [2.1 数値型](#21-数値型)
   - [2.2 文字列型](#22-文字列型)
   - [2.3 真偽値](#23-真偽値)
   - [2.4 変数](#24-変数)
   - [2.5 オブジェクト](#25-オブジェクト)
   - [2.6 データ型](#26-データ型)
   - [2.7 変数表示](#27-変数表示)
   - [2.8 入力処理](#28-入力処理)
   - [2.9 乱数](#29-乱数)
   - [2.10 条件分岐](#210-条件分岐)
   - [2.11 ループ](#211-ループ)
   - [2.12 リスト](#212-リスト)
   - [2.13 タプル](#213-タプル)
   - [2.14 ディクショナリ](#214-ディクショナリ)
   - [2.15 セット](#215-セット)
   - [2.16 コレクションまとめ](#216-コレクションまとめ)
   - [2.17 組み込み関数](#217-組み込み関数)
   - [2.18 独自関数](#218-独自関数)
   - [2.19 無名関数](#219-無名関数)
   - [2.20 ローカル変数とグローバル変数](#220-ローカル変数とグローバル変数)
3. **[Python文法(発展)](#3-python文法発展)**
   - [3.1 モジュールとライブラリ](#31-モジュールとライブラリ)
   - [3.2 クラス](#32-クラス)
   - [3.3 ファイルの入出力](#33-ファイルの入出力)
   - [3.4 例外処理](#34-例外処理)
   - [3.5 JSONデータ処理](#35-jsonデータ処理)


## 1 プログラミング入門 

### 1.1 プログラミングとは

ある目的のために作り出す、コンピュータに対する命令を並べたものを**プログラム**と呼びます。

コンピュータとコミュニケーションを取るために、プログラムを行うプロセスが**プログラミング**に当たります。

プログラミングをする際には、一定の規則に従って記述された**プログラミング言語**を使用します。  
これらの言語では、特定の命令を書くと特定の処理が行われるように決められています。  
このような規則のことを**文法**と呼びますが、文法は使うプログラミング言語によって異なります。

プログラミングを学ぶ最初のステップは、まさにこの文法を理解することから始まります。

### 1.2 Pythonとは

Pythonは直感的で非常に分かりやすいプログラミング言語で、シンプルな記述が可能です。  
初心者でも簡単に学ぶことができます。

さらに、Pythonには多くのライブラリが公開されており、これらを活用することで高度な機能を比較的容易に実現できます。  
 特にAI関連のライブラリは豊富で、機械学習やデータ分析の分野で幅広く利用されています。

Pythonの魅力は、開発環境だけでなく、無料で利用できるライブラリの多様性にもあります。  
費用をかけずに、Pythonを使ったプログラミングの世界に飛び込むことができます。

Pythonを学習する際には、学習の中でどのようなことを実現したいかを考えることが非常に重要です。

Pythonで出来ることは以下のような領域になります。

#### WEBアプリケーション開発




（そのほかのツールは[こちら](https://zenn.dev/neka_nat/articles/f2f5b6ebeb049a)などを参照してください）
  - [Flask](https://msiz07-flask-docs-ja.readthedocs.io/)  
    必要最低限の機能だけを揃えた軽量Webアプリケーションフレームワーク。  
    分かりやすい説明記事は[こちら](https://toukei-lab.com/python-flask)。
  - [Django](https://docs.djangoproject.com/ja/5.0/)  
    フルスペックのWebアプリケーションフレームワーク。Flaskより多くの機能を提供する。  
    分かりやすい説明記事は[こちら](https://toukei-lab.com/django)。  
    分かりやすいFlaskとの比較記事は[こちら](https://toukei-lab.com/flask-django)。
  - [Fastapi](https://docs.djangoproject.com/ja/5.0/)  
    高速なAPIフレームワークで、非常に高速で直感的なAPIを構築できる。  
    分かりやすい入門Zenn記事は[こちら](https://zenn.dev/sh0nk/books/537bb028709ab9)。  
    分かりやすいFlaskとの比較記事は[こちら](https://zenn.dev/nameless_sn/articles/flask_vs_fastapi)。
  - [Streamlit](https://streamlit.io/)
    データの可視化や分析を行うWebアプリを簡単に作れるフレームワーク。  
    分かりやすい説明記事は[こちら](https://toukei-lab.com/streamlit)。  
    一通りの機能の紹介記事は[こちら](https://data-analytics.fun/2022/08/28/streamlit-recap/)

#### データ分析



  - [Numpy](https://numpy.org/ja/)
    数値計算ライブラリで、高速な多次元配列オブジェクトやそれを操作するためのツールが提供される。  
    分かりやすい入門Qiita記事は[こちら](https://qiita.com/moe_713/items/671c8c912f6e8d6c7442)。  
  - [Pandas](https://pandas.pydata.org/)  
    データ解析ライブラリで、データの整形や加工、解析が容易に行える。  
    分かりやすい入門Qiita記事は[こちら](https://qiita.com/ysdyt/items/9ccca82fc5b504e7913a)。
  - [matolotlib](https://matplotlib.org/)  
    可視化ライブラリで、2Dグラフや3Dグラフを描画するためのツールが提供されている。  
    分かりやすい入門Qiita記事は[こちら](https://qiita.com/nkay/items/d1eb91e33b9d6469ef51)。
  - [Seaborn](https://seaborn.pydata.org/)  
    Matplotlibをベースにした可視化ライブラリで、美しいグラフを簡単に描画できる。  
    分かりやすい記事群は[こちら](https://datawokagaku.com/tag/seaborn/)。
  - [Plotly](https://plotly.com/python/)  
    可視化ライブラリで、インタラクティブなグラフや図を作成するためのツールが提供されている。  
    分かりやすい記事は[こちら](https://data-analytics.fun/2021/11/19/plotly-summary/)。
  - [SciPy](https://scipy.org/)  
    科学技術計算のためのライブラリで、数値計算や最適化、統計など多岐に渡る機能が提供されている。
  - [Polars](https://pola.rs/)  
    高速なデータフレームライブラリで、大規模なデータセットの処理や分析に適している。  
    分かりやすいPandasとの比較記事は[こちら](https://qiita.com/_jinta/items/fac13f09e8e8a5769b79)。

#### 機械学習・Ai



  - [scikit-learn](https://scikit-learn.org/)   
    機械学習ライブラリで、様々な機械学習アルゴリズムやデータ前処理の機能が提供されている。  
    分かりやすい説明記事は[こちら](https://toukei-lab.com/scikit-learn)。
  - [PyTorch](https://pytorch.org/)  
    機械学習ライブラリで、ニューラルネットワークの構築やトレーニングが容易に行える。  
    分かりやすい説明記事は[こちら](https://toukei-lab.com/pytorch)。
  - [TensorFlow](https://www.tensorflow.org/?hl=ja)  
    Googleが開発したオープンソースの機械学習ライブラリで、  
    ニューラルネットワークの構築やトレーニング、デプロイメントが可能である。  
    分かりやすい入門Qiita記事は[こちら](https://qiita.com/junichiro/items/8886f3976fc20f73335f)。
  - [Transformer](https://ja.wikipedia.org/wiki/Transformer_%28%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%83%A2%E3%83%87%E3%83%AB%29)  
    自然言語処理（NLP）タスクに特化したライブラリで、BERTやGPTなどの大規模な事前学習済みモデルを提供している。  
    分かりやすいZenn記事は[こちら](https://zenn.dev/zenkigen_tech/articles/2023-01-shimizu)。

#### ゲーム（GUI）アプリ開発



（ライブラリの比較記事は[こちら](https://www.simugrammer.com/python_gui_matome/)）
  - [Tkinter](https://docs.python.org/ja/3/library/tkinter.html)  
    GUIアプリケーションを作成するためのツールキット。  
    分かりやすい記事群は[こちら](https://chantastu.hatenablog.com/archive/category/GUI%E4%BD%9C%E6%88%90)。
  - [Pygame](https://www.pygame.org/)  
    2Dゲームを作成するためのライブラリで、ゲーム開発に必要な機能を提供している。

#### スクレイピング


（分かりやすいサイトは[こちら](https://ai-inter1.com/python-webscraping/)）
  - [Requests](https://requests.readthedocs.io/)  
    HTTPライブラリで、HTTPリクエストを簡単に送信するためのツールが提供されている。  
    分かりやすい記事は[こちら](https://ai-inter1.com/python-requests/)。
  - [Beautiful Soup](https://www.crummy.com/software/BeautifulSoup/bs4/doc/)  
    HTML/XML解析ライブラリで、Webスクレイピングやデータ抽出に使用される。  
    分かりやすい記事は[こちら](https://ai-inter1.com/beautifulsoup_1/)。
  - [Selenium](https://selenium-python.readthedocs.io/)  
    Webブラウザを自動化するためのツールで、Webアプリケーションのテストやスクレイピングに使用される。  
    分かりやすい記事は[こちら](https://ai-inter1.com/python-selenium/)。

### 1.3 プログラミングの進め方

Pythonの実行環境には様々なものがありますが、有名どころである**Goolge Colaboratory** や**Jupyter Notebook** はNotebookタイプです。

Notebookタイプでは、コードを追加したいとき（プログラムを実行する）に**Codeセル**を、メモを残したいときに**Textセル**を追加します。   
Textセルでは、**Markdown記法**を用いることで見栄えの良いテキストを作成することができます。



特にGoolge Colaboratoryは、[Google Research](https://research.google/)が提供する無料のクラウドベースPython実行環境です。

初期設定がほぼ不要であること、Googleのサーバー上で動くことなどが大きな特徴です。

簡単な初期設定を終えるとすぐに、プログラムを実行できるようになります。

以下のサンプルコードを実行してみましょう。（実行ボタンをクリックするか、「Ctrl」＋「Enter」を押す）


```python
1 + 2
```




    3



「**コンソール**」と呼ばれる部分に結果が出力されます。

### 1.4 print関数

print関数を用いることで、printの後ろの()の中に書いた値を出力できます。


```python
print("Hello World!")
```

    Hello world
    

print関数の途中で改行したいときは、**`"\n"`** を途中に挿入します。


```python
print("Hello World!\nWelcome to Python!")
```

    Hello World!
    Welcome to Python!
    

endオプションを指定すると、改行を防止することができます。


```python
print("Hello World!", end=" ")  # 文の間に空白" "を空ける
print("Welcome to Python!", end=", ")  # 文の間に","をつける
print(25)
```

    Hello World! Welcome to Python!,25
    

### 1.5 コメント


プログラムはプログラミング言語で書かれるため、理解しにくい部分もあるかもしれません。  
そのような場合には、「コメント」を使って補足することができます。

Python言語では「#」記号を利用して「コメント」を入力します。  
「#」記号より文末までが、「コメント」という扱いになります。

コメントの各行は (コメント内でインデントされたテキストでない限り)「#」とスペースひとつで始めることになります。


```python
# Hello Worldを表示するよ！
print("Hello World!")  # print関数を使って画面に表示するよ
```

「一時的にプログラムを無効化したい」場合にも、コメントを利用することがあります。  
このようにプログラムを無効化することを「**コメントアウト**」と呼びます。


```python
# 一時的にプログラムを無効化！
# print("Hello World!")
```

コメントアウトしたいコード部分をドラッグか「Ctrl」＋「A」を押すかして選択した後、  
「Ctrl」＋「/」を押すことで、自動でコメントアウトをすることができます。

### 1.6 エラーへの対処方法

プログラミングには、時折**エラー**が発生します。文法の誤りや正しくない処理を行った場合に、エラーが発生します。  
エラーが起こると、プログラムの実行が停止し、その原因や場所がエラーメッセージとして表示されます。

エラーメッセージを理解することは重要です。

分からない場合は、インターネットで検索してみることをお勧めします。  
同じような問題を抱えた人が解決策を共有していることがあります。

### 1.7 Pythonプログラミングにおける注意

#### 行の先頭から書く

Pythonプログラムは、基本行の先頭から書きます。


```python
print("Hello World!")       # 行頭からプログラムが始まる OK
    #print("Hello World!")   # 行頭がズレている NG
```


      File "<ipython-input-1-b83c2386e626>", line 2
        print("Hello World!")   # 行頭がズレている NG
        ^
    IndentationError: unexpected indent
    


実行すると、2行目でエラーが発生します。

行頭の空白やタブのことを「**インデント**」と呼びます。  
Pythonでは「インデント」のルールが明確に決まっています。

インデントについて、原則スペース4個で書くこととされています。  
インデントにタブとスペースを混ぜることは禁止されているので注意が必要です。

複数の行に対してインデントを入れたい場合には、行を複数選択してから[TAB]キーを押します。

反対に、インデントを削除したい場合には、行を複数選択してから[SHIFT]+[TAB]キーを押します。


#### 1行に1命令

Pythonのプログラムでは、通常、1行に1つのプログラムを書きます。  
~~複数のプログラム実行命令を1行に詰め込むことはできません。~~


```python
# 1行に2つの命令
#print("Hello") print("World")
```


      File "<ipython-input-2-b474b958ca8e>", line 2
        print("Hello") print("World")
                       ^
    SyntaxError: invalid syntax
    
実行すると、エラーが発生します。

※24/3/1追記　単純文という書き方があるみたいです！コメントありがとうございます！
https://docs.python.org/ja/3/reference/simple_stmts.html

```python
# 単純文
print("Hello");print("World")
```

#### 全角スペースの罠

Pythonでは、コメントや文字列以外の箇所では「全角スペース」の使用は許可されていません。


```python
# コメントで「　」       # コメントの中はOK
print("Hello　World")   # 文字列の中はOK
#print(24　)             # プログラムの中はNG
```

実行すると、3行目でエラーが発生します。

Pythonでは、コメントを入れる際に、間違って全角スペースが使われることがあります。  

全角スペースは目で見て判別しにくいため、注意が必要です。



## 2 Python文法(基礎)

### 2.1 数値型

数値型(Numeric)には**整数**、**浮動小数点数**、複素数 の3つがあります。  


```python
print(25)     # 整数型
print(25.25)  # 浮動小数点数
```

    25
    25.25
    

以下の四則演算をすることができます。


加算と減算は、数学の記号と同様に、プラス記号(+)とマイナス記号(-)を使用します。  
一方、乗算と除算については、プログラミング言語特有の記号を使用します。


```python
# 加算
7 + 3
```

```
10
```

```python
# 減算
7 - 3
```

```
4
```

```python
# 乗算
7 * 3
```

```
21
```

```python
# 除算(商、値は実数)
7 / 3
```

```
2.3333333333333335
```

```python
# 除算(商、値は整数)
7 // 3
```

```
2
```

```python
# 除算(剰余)
7 % 3
```

```
1
```

```python
# 冪乗
7 ** 3
```

```
343
```

算術演算を組み合わせて、より複雑な計算を行うこともできます。

演算子の結合強度は次のようになっています：冪乗 > 乗算・除算 > 加算・減算。  

括弧がある場合、その内部の計算が優先されます。


```python
(1 + 2) * 3 + 5**2
```




    34




```python
2 + 3 * 5
```




    17




```python
(2 + 3) * 5
```




    25




```python
2 ** 3 * 5
```




    40




```python
2 ** (3 * 5)
```




    32768



演算記号の前後（加えて、コンマの後）には、スペース1個を入れるのが原則です。  

ただし、グルーピングを表したいときには、スペースを入れないこともあります。

### 2.2 文字列型

Pythonの文字列は『**シングルクォーテーション**』か『**ダブルクォーテーション**』で囲みます。  
単数文字か複数文字かの区別はなく、どちらを使ってもよいです。  

囲むときは同じものをセットで使う必要があることに注意しましょう。  
『**ダブルクォーテーション**』を使うことが多いようです。


```python
print('Hello World!')  # シングルOK
print("Hello World!")  # ダブルOK
#print('Hello World!")  # 異なる場合はNG
```




    False



文字列においては、以下の演算をすることができます。



```python
# 連結
print("Hello" + "World!")
```

    HelloWorld!
    


```python
# 反復
print("Hello" * 3)
```

    HelloHelloHello
    

数値型と文字列型を結合することは不可能なので注意が必要です。


```python
print(7 + 4)      # 数値型の結合
print("7" + "4")  # 文字列型の結合
```

    11
    74
    

特殊な文字列（例えば「"」や「'」など）を入力する際には、**エスケープシーケンス**という特殊な文字列を使用する必要があります。

「\」と文字の組み合わせで表現します。


```python
print("改行\nしてみる")
print("Tab\tしてみる")
print("ダブルクォーテーションを\"表示してみる")
print("シングルクォーテーションを\'表示してみる")
print("\\マークを表示してみる")

```

    改行
    してみる
    Tab	してみる
    ダブルクォーテーションを"表示してみる
    シングルクォーテーションを'表示してみる
    \マークを表示してみる
    

### 2.3 真偽値

**真偽値（boolean）** とは、コンピューターの世界において、真偽を表すために用いられる基本的な概念です。

Pythonにおいては、**`True`** (=真)と **`False`**  (=偽)で表されます。

条件が成立したときは`True`、しなかったときは`False`となります。

何らかの条件を立てるときには、**条件式**を立てることになります。

ここで使われる演算子が**比較演算子**です。比較のパターンは6種類あります。


```python
print(7 > 4)   # (左)が(右)より大きい
print(7 < 4)   # (左)が(右)より小さい
print("")
print(7 >= 4)  # (左)が(右)以上である
print(7 <= 4)  # (左)が(右)以下である
print("")
print(7 == 4)  # (左)が(右)と等しい
print(7 != 4)  # (左)が(右)と等しくない

```

    True
    False
    
    True
    False
    
    False
    True
    

文字列型同時を比較するときは、少しだけ意味合いが変わってきます。


```python
name1 = "Japan"
name2 = "America"

print(name1 == name2)  # "Japan"と"America"は同じではないのでFalse
print(name1 != name2)  # "Japan"と"America"は同じではないのでTrue
print()
print(name1 < name2)  # "Japan"は"America"より「辞書的に前」ではないのでFalse
print(name1 > name2)  # "Japan"は"America"より「辞書的に後」なのでTrue
print()
print(name1 <= name2)  # "Japan"は"America"より「辞書的に前」ではないのでFalse
print(name1 >= name2)  # "Japan"は"America"より「辞書的に
```

    False
    True
    
    False
    True
    
    False
    True
    

真偽値に関する計算（論理計算）において、Pythonでは**論理積`and`**、**論理和`or`**、**否定`not`** がサポートされています。


```python
# 両方の条件が満たされたらTrue
True and False
```




    False




```python
# どちらかの条件が満たされたらTrue
True or False
```




    True




```python
# 条件が満たされなかったらTrue
not True
```




    False



### 2.4 変数

**変数**は、データを格納するためにコンピュータ内部に準備する箱のようなものです。  

変数に値を保存することを**代入**と言い、その値を取り出して利用することを**参照**と言います。


Pythonで変数を作成する場合は、必ず**変数名**と**セットしたい値**を同時に書く必要があります。


```python
name = "Japan"  # nameという変数に、文字列"Japan"を代入
number = "81"   # numberという変数に、文字列の"81"を代入
age = 21        # ageという変数に、整数の"21"を代入

print(name)
print(number)
print(age)
```

    Japan
    81
    21
    

Pythonでは、変数名や関数名の命名規則には**スネークケース**（**snake_case**）と呼ばれるスタイルを適用するのが一般的です。  
これは全ての文字を小文字にして、単語の間をアンダースコアで区切る書き方です。

一方、クラス名の命名規則には**UpperCamelCase**と呼ばれるスタイルを適用します。  
これは単語の先頭を大文字で表記し、単語の間にアンダースコアを使用しない書き方です。

関数名や変数名に使用できない単語を**予約語**と呼びます。

予約語を用いてしまうと、構文エラー（SyntaxError)が起こってしまいます。


```python
import keyword
import pprint

print(len(keyword.kwlist))
# 35

pprint.pprint(keyword.kwlist, compact=True)
# ['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break',
#  'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for',
#  'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not',
#  'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
```

    35
    ['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break',
     'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for',
     'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not',
     'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
    

プログラミング言語では、`=`は「等しい」という意味ではなく、「代入する」という意味で使用されます。

一度保存した値は何度でも利用でき、上書きされるまで残り続けます。  
変数の値を上書きすることを「**再代入**」と呼ぶこともあります。再代入の際も、代入と同様の記法を使用します。


```python
# age+1をageに再代入する（変数値の更新）
age = 21
print(f"age: {age}")

age = age + 1
print(f"age + 1: {age}")
```

    age: 21
    age + 1: 22
    

自己代入には省略形があります。


```python
# 足し算（x = x+4と同じ意味）
x = 7
print(f"x: {x}")
x += 4
print("x += 4:", x)

# 引き算（x = x-4と同じ意味）
x = 7
x -= 4
print("x -= 4:", x)

# 掛け算（x = x*4と同じ意味）
x = 7
x *= 4
print("x *= 4:", x)

# 割り算（商は実数）（x = x/4と同じ意味）
x = 7
x /= 4
print("x /= 4:", x)

# 割り算（商は整数）（x = x//4と同じ意味）
x = 7
x //= 4
print("x //= 4:", x)

# 剰余算（x = x%4と同じ意味）
x = 7
x %= 4
print("x %= 4:", x)

# 階乗（x = x**4と同じ意味）
x = 7
x **= 4
print("x **= 4:", x)
```

    x: 7
    x += 4: 11
    x -= 4: 3
    x *= 4: 28
    x /= 4: 1.75
    x //= 4: 1
    x %= 4: 3
    x **= 4: 2401
    

コンピュータに対する命令それぞれに対応するものを、**式**と言います。  

式を処理して値を得ることを式の**評価**といいます。得られた値のことを**評価値**と呼びます。  
複数の式が並んでいる場合、その中で最後の式の評価結果が全体の評価結果となります。  


代入式

```
<変数> = <式>
```

ではまず右辺の式が評価され、その値が左辺の変数に代入されます。

print関数のように、右辺の式の評価値がない場合も存在します。


```python
# 右辺の式の評価値がない場合の代入式
x = print(7 + 4)
print("print(x):", x)
```

    11
    print(x): None
    

Pythonでは、値が存在しないことを示すために`None`というデータが用意されています。  

`None`に対する演算は限られていますが、特定のデータがNoneであるかどうかを判定するには、  
**`is`演算子**を使用します。


```python
# is演算子
x = print(2 + 3)
print("x is None:", x)
```

    5
    x is None: None
    


```python
x = 1
y = 1
print("x is y:", x is y)
```

    x is y: True
    

### 2.5 オブジェクト

Pythonでは **『オブジェクトID』** を使って、オブジェクトの識別が行われます。

![python_3-1.png](https://bit.ly/3koC4t4)

オブジェクトIDは**id関数**を使うことで取得できます。


```python
# 環境によって違う値になります
print("id(19):", id(19))
print("id(3.14):", id(3.14))
print('id("Hello"):', id("Hello"))
print("id(True):", id(True))
```

    id(19): 134518170567472
    id(3.14): 134517265041328
    id("Hello"): 134517742549360
    id(True): 97697713255456
    

Pythonでは、変数は値ではなく**オブジェクトID**を管理しています。

![](https://bit.ly/3iSYIcD)

そのため、Pythonにおける「変数への代入」とは、  
**「変数にオブジェクトIDを設定する」** ことを指します。


```python
# idの確認
print("オブジェクトの生成")  # 実行時にオブジェクトが生成される
print(f"before: {id(19)}")
print(f"after: {id(20)}\n")

# 変数に代入（オブジェクトIDの設定）
before_age = 19
after_age = 19
print("代入直後")
print(f"before : {id(before_age)}")
print(f"after : {id(after_age)}\n")

# 変数の値を更新（オブジェクトIDの変更）
# 変数が参照先オブジェクトに置き換わる
# 例：id(after_age)→id(20)
after_age += 1
print("更新直後")
print(f"before : {id(before_age)}")
print(f"after : {id(after_age)}")
```

    オブジェクトの生成
    before: 132724925334320
    after: 132724925334352
    
    代入直後
    before : 132724925334320
    after : 132724925334320
    
    更新直後
    before : 132724925334320
    after : 132724925334352
    

オブジェクトに何らかの操作を行うための関数のことを**メソッド**といいます。  
オブジェクトの種類に応じて多くのメソッドがあります。

```
オブジェクト.メソッド名(引数)
```

文字列型のオブジェクトに適用できるメソッドには、以下のようなものがあります。


```python
# 文字列オブジェクトを生成
name = "Sato Taro"

# 文字列を変換するメソッド

# すべての文字を小文字に変換
print(f"{name.lower()} : lower")

# すべての文字を大文字に変換
print(f"{name.upper()} : upper")

# 指定した文字列の個数を取得
print(f"{name.count('o')}")

# 指定した文字列に置換
print(f"{name.replace('Taro','Hanako')}")
```

    sato taro : lower
    SATO TARO : upper
    2
    Sato Hanako
    


```python
# 文字列を区切る
filename = "sample_1.py"

# splitメソッド
# 引数を省略した場合は空白で分割
print(f'.split(".")[0] --> {filename.split(".")[0]}')  # "."の左側の文字列を出力
print(f'.split(".")[1] --> {filename.split(".")[1]}')  # "."の右側の文字列を出力

# re.split()
# 複数条件で文字列を分割できる
import re
print(f"re.split('[_.]', filename)[0] --> {re.split('[_.]', filename)[0]}")  # "_"の左側の文字列を出力
print(f"re.split('[_.]', filename)[1] --> {re.split('[_.]', filename)[1]}")  # "_"の右側の文字列を出力
print(f"re.split('[_.]', filename)[2] --> {re.split('[_.]', filename)[2]}")  # "."の右側の文字列を出力
```

    .split(".")[0] --> sample_1
    .split(".")[1] --> py
    re.split('[_.]', filename)[0] --> sample
    re.split('[_.]', filename)[1] --> 1
    re.split('[_.]', filename)[2] --> py
    

### 2.6 データ型

プログラムで扱うことのできるデータの種類を**データ型**といいます。  
Pythonにおけるデータ型は以下表のようなものがあります。

- 文字列型：**`str`**
- 整数：**`int`**
- 浮動小数点数：**`float`**
- 真偽値：**`bool`**

**Pythonでは、変数代入した値によってそのデータ型が決まります。**

**type関数**を使うと、変数にどのような型の値が格納されているかを調べることができます。


```python
name = "Japan"  # 文字列型str
number = "81"   # 文字列型str
age = 21        # 整数int

print(type(name))
print(type(number))
print(type(age))
```

    <class 'str'>
    <class 'str'>
    <class 'int'>
    

データ型を別のものに変換する際には、**型変換**（**キャスト**）を行います。

```
変換先の型名（式）
```


```python
name = "Japan"
number = 81
print(type(number))  # 整数

new_number = str(number)  # 文字列型に変換
print(type(new_number))

new_name = list(name)  # リスト型に変換
print(new_name)

# print(name + "の番号は" + number + "です")  # エラー発生
print(name + "の番号は" + new_number + "です")
```

    <class 'int'>
    <class 'str'>
    ['J', 'a', 'p', 'a', 'n']
    Japanの番号は81です
    

整数と浮動小数点数の間で演算が行われる場合は、  
浮動小数点数に揃えられてから演算が行われます。  

このように自動的に型変換が行われる仕組みを**暗黙の型変換**といいます。  
数値と文字の間では行われません。


```python
number = 81
print(type(number))  # 整数

minus = 3.7
print(type(minus))  # 浮動小数点数

number -= minus  # numberが浮動小数点に揃えられて演算
print(type(number))
```

    <class 'int'>
    <class 'float'>
    <class 'float'>
    

### 2.7 変数表示

変数の値をprint関数で表示したいときに用いられる方法の一つが、**formatメソッド**です。

文字列の様々な場所に逐一値を埋め込むことができます。

値を埋め込みたい場所に「**{}**（**プレースホルダー**）」を書きます。  
formatのカッコ内に、埋め込みたい値をカンマ区切りで並べます。


```python
name = "Japan"
number = 81

print("{}の番号は{}です".format(name, number))
```

    Japanの番号は81です
    


```python
# 数値を10桁の幅で表示する
# 先頭に3文字分の余白（「整数部3桁 + ドット1桁 + 小数部3桁」）

num = 123.456
print('{:10}'.format(num))
# =>    123.456
```

       123.456
    


```python
# 小数点以下の桁数を1桁と指定

num = 123.456
print('{:.1f}'.format(num))
# => 123.5
```

    123.5
    

変数の値をprint関数で表示したいときに用いられる方法の一つが、**f文字列**です。

プレースホルダーの中に埋め込みたい値や式を入れることができます。


```python
name = "Japan"
number = 81

print(f"{name}の番号は{number}です")
```

    Japanの番号は81です
    


```python
# 数値を10桁の幅で表示する
# 先頭に3文字分の余白（「整数部3桁 + ドット1桁 + 小数部3桁」）

num = 123.456
print(f'{num:10}')
# =>    123.456
```

       123.456
    


```python
# 小数点以下の桁数を1桁と指定

num = 123.456
print(f'{num:.1f}')
# => 123.5
```

    123.5
    

### 2.8 入力処理

変数には、キーボードから入力した文字列や数字を代入することができます。  
そのような入力を行える関数が**input関数**です。  

input関数で入力された値は**文字列型**として扱われます。


```python
name = "Taro"

print("年齢を入力してください")
age = input()  # 入力するよう促されます

print(f"{name}さんの年齢は {age}歳 です ")
print(f"4年後は {int(age)+4}歳 です")  # 文字列型→整数型に変換
```

    年齢を入力してください
    20
    Taroさんの年齢は 20歳 です 
    4年後は 24歳 です
    

input関数では引数で入力を促すメッセージを指定することが可能です。


```python
name = "Taro"

age = input("年齢を入力してください\n")  # 引数でメッセージ指定

print(f"{name}さんの年齢は {age}歳 です ")
print(f"4年後は {int(age)+4}歳 です")  # 文字列型→整数型に変換
```

    年齢を入力してください
    20
    Taroさんの年齢は 20歳 です 
    4年後は 24歳 です
    

### 2.9 乱数

**乱数**とは、ランダムで何が出るか分からない数字のことです。  
  

Pythonで乱数を扱う場合、標準ライブラリの**random**をインポートする必要があります。  
使う前に`import random`の記述が必要です。



```python
# ライブラリのインポート
import random

# 乱数シードを固定し乱数生成器を初期化できる
random.seed(0)

# 0.0以上、1.0未満のランダムな実数を返す
print(random.random())

# 同じシードで初期化しているので同じ乱数値が生成される
random.seed(0)
print(random.random())

print("------------------------------")

# 最小値 ≦ N ≦ 最大値となるランダムな実数Nを返す
print(random.uniform(0, 20))

# 最小値 ≦ I ≦ 最大値となるランダムな整数Iを返す
print(random.randint(0, 20))

# range(start, stop, step)の要素からランダムに選ばれた整数を返す
# デフォルト値はstart=0, step=1
print(list(range(10)), random.randrange(10))

# データからランダムに要素を1つ選んで返す
print(random.choice("ABCDEFG"))

# リストの要素をランダムにシャッフルする
alpha_list = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
print(alpha_list)

random.shuffle(alpha_list)
print(alpha_list)
```

    0.8444218515250481
    0.8444218515250481
    ------------------------------
    15.159088058806049
    13
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 0
    C
    ['A', 'B', 'C', 'D', 'E', 'F', 'G']
    ['A', 'G', 'B', 'C', 'F', 'D', 'E']
    

### 2.10 条件分岐

プログラムの基本的な処理の1つに**条件分岐**があります。  
条件によって実行する処理を変えることができるようになります。

Pythonにおける分岐は「**if文**」です。



プログラミングにおける処理のまとまりのこと**ブロック**と言います。

Pythonではインデント（スペース4つ）が挿入されている部分をブロックとみなして処理しています。  
複数の連続する処理を実行する際には、すべてにインデントが必要です。

適切にインデントが挿入されていないとエラーとなります。

`if`文の構文は3つあります。フォーマットは以下の通りです。


- **`if-else`構文**（基本形）
```python
if <条件式>:
    <(条件式がTrueのときに実行する)処理>
else：
    <(条件式が成立しなかったときの)処理>
```

- **`if`のみの構文**（条件式が成立しなかったときには何もしない場合）
```python
if <条件式>:
    <(条件式がTrueのときに実行する)処理>
```

- **`if-elif`構文**（複数の条件式が必要な場合）
```python
if <条件式0>:
    <(条件式0がTrueのときに実行する)処理>
elif <条件式1>:
    <(条件式0がFalse、条件式1がTrueのときに実行する)処理>
else:
    <(すべての条件式がFalseのときに実行する)処理>
```

下の例では変数`x`の絶対値を計算し、その結果を`y`に格納しています。


```python
x = -7
if (x < 0):
    y = - x
else:
    y = x
y
```




    7



(条件式が`True/False`となったときに実行される)処理の前のインデントによって、  
似たようなコードでも動作が全く異なることがあります。


```python
# 例1
x = 1
if (x < 0):
    x = - x
    x = - x
x
```




    1




```python
# 例2
x = 1
if (x < 0):
    x = - x
x = - x
x
```




    -1



下の例は、**`if-else`構文**を用いた偶数奇数判定をするプログラムです。  


```python
import random

# 0～100までの整数をランダムに取得
number = random.randint(0,101)
print(f"この科目の合計点は{number}点です")

# 偶数奇数判定
result = number % 2

if result == 0 :
    print(f"{number} は偶数です")
else :
    print(f"{number} は奇数です")
```

    この科目の合計点は62点です
    62 は偶数です
    

下の例は、**`if-elif`構文**を用いた成績判定プログラムです。


```python
import random

# 0～100までの整数をランダムに取得
point = random.randint(0,101)
print(f"この科目の合計点は{point}点です")

# 0点以上60点未満
if point >= 0 and point < 60 :
    print("成績はEです")

# 60点以上70点未満
elif point >= 60 and point < 70 :
    print("成績はDです")

# 70点以上80点未満
elif point >= 70 and point < 80 :
    print("成績はBです")

# 80点以上90点未満
elif point >= 80 and point < 90 :
    print("成績はAです")

# 90点以上100点以下
elif point >= 90 and point <= 100 :
    print("成績はSです")

# エラー処理
else :
    print("点数を正しく入力してください")
```

    この科目の合計点は38点です
    成績はEです
    

`if`文は**三項演算子**という書き方を使うと1行で記述できます。

```python
# if文（通常）
if <条件式>:
    <(条件式がTrueのときに実行する)処理>
else：
    <(条件式が成立しなかったときの)処理>
```

```python
# 三項演算子
<(True時の)処理> if <条件式> else <(False時の)処理>
```

偶数奇数判定をするプログラムを1行で記述しましょう。


```python
import random

# 0～100までの整数をランダムに取得
number = random.randint(0,101)
print(f"この科目の合計点は{number}点です")

# 偶数奇数判定
result = number % 2

print(f"{number} は偶数です") if result==0 else print(f"{number} は奇数です")
```

    この科目の合計点は26点です
    26 は偶数です
    

### 2.11 ループ

プログラムにおいて、似たような処理を繰り返し実行したい、ということはよくあります。


```python
# 1から10までの和
x = 0
x = x + 1
x = x + 2
x = x + 3
x = x + 4
x = x + 5
x = x + 6
x = x + 7
x = x + 8
x = x + 9
x = x + 10
x
```




    55



似たような処理に対して**ループ**を利用することで、効率的に書くことができます。


```python
# 1から10までの和（for文の場合）
x = 0
for n in range(1, 11):
    x = x + n
x
```




    55



ループを利用することによって、共通部分の処理を1回だけ書けば良いことになります。

Pythonでよく使われるループは2種類あり、`for`文と`while`文があります。フォーマットは以下の通りです。

- `for`文

```python
for <変数> in <イテラブル>:
    <処理>
```

- `while`文

```python
while <条件式>:
    <(条件式がTrueの間だけ実行する)処理>
```

**イテラブル**は、要素を順番に取り出すことができるオブジェクトのことです。

主なイテラブルの例としては、文字列、リスト、タプル、辞書、セット、rangeオブジェクトなどが挙げられます。

`for`文ではイテラブルのデータを順に変数に代入して処理を行う、ということを繰り返していきます。  
そして最後のデータまで処理したら`for`文を抜けます。

`while`文は条件式が`True`である間、その中の処理を繰り返し実行します。  
条件式が`False`になった場合、`while`文から抜け出します。

`if`文と同様、`for`文・`while`文もインデントによってブロックを認識するので、注意が必要です。

`range`オブジェクトは、Pythonにおいて連続した整数の範囲を表現するための特別なオブジェクトです。  

主にforループで繰り返し処理を行う際に使用されます。



`range`オブジェクトは、`range()`関数を使って作成します。  
`range()`関数は以下のような書式を持ちます。

``` python
range(start, stop, step)
```

- `start`: 範囲の開始値（デフォルトは0）
- `stop`: 範囲の終了値（この値は含まれない）
- `step`: 値の増分（デフォルトは1）

回数の決まっている繰り返しには、`for`ループのイテラブルとして`range`オブジェクトを使うことが多いです。

「**終了値-1**」回の反復処理が行われます。

``` python
for 変数 in range(start, stop, step)
```

回数の決まっていない繰り返しには、**`while`ループ**を使用することが多いです。  



```python
# 1から10までの和（while文の場合）
x = 0
n = 1
while (n <= 10):
    x = x + n
    n = n + 1
x
```

変数`i`のように、繰り返すたびにその値が変化し、繰り返しの条件となる変数のことを  
**カウンタ変数**または**ループ変数**（**ループカウンタ**）といいます。  

変数`i`の値を`while`ブロックの中で更新し忘れると、繰り返しが終了しません。  
このようないつまでも続く繰り返しのことを**無限ループ**と呼びます。

あえて無限ループを作るときは以下のようにします。
``` python
while True:
  <(条件式がTrueの間だけ実行する)処理>
```



```python
for _ in range(3):
    print("Hello")
print("終了しました")
```

    Hello
    Hello
    Hello
    終了しました
    

for文を使って九九を表示してみましょう。


```python
# 縦方向のループ用
for num1 in range(1, 10):

    # 横方向のループ用
    for num2 in range(1, 10):

        # 改行なしで2ケタ表示
        print(f"{num1 * num2:2d} " , end="")

    # 1行分が終わったので改行を実施
    print()
```

     1  2  3  4  5  6  7  8  9 
     2  4  6  8 10 12 14 16 18 
     3  6  9 12 15 18 21 24 27 
     4  8 12 16 20 24 28 32 36 
     5 10 15 20 25 30 35 40 45 
     6 12 18 24 30 36 42 48 54 
     7 14 21 28 35 42 49 56 63 
     8 16 24 32 40 48 56 64 72 
     9 18 27 36 45 54 63 72 81 
    

ループの中では、繰り返すための処理を制御するための特別なキーワードが使えます。  
これらをうまく活用することで目的のループ処理を行うことができます。

ループの中で処理を最後まで行わずに途中で中断したいときに使う文が **`break`文** です。

ループそのものを中断し、ループの次に記述された処理へと進みます。


```python
# 1から10までの偶数の和を求めるプログラム
sum = 0
for num in range(11):
    if num%2 == 0:
        sum += num

print(f"偶数の和：{sum}")
```

    偶数の和：30
    

特定の条件を満たした場合に、次のループ処理に移行したいときに使う文が **`continue`文** です。

ループの現在の回だけを中断してループの先頭へ戻り、次の回のループを継続します。  


```python
# 1から10までの偶数の和を求めるプログラム
sum = 0
for num in range(11):
    if num%2 != 0:
        continue
    sum += num

print(f"偶数の和：{sum}")
```

    偶数の和：30
    


```python
import random

count = 1  # 成績処理回数

while True :
    point = random.randint(-10, 111)  # -10～110までの整数をランダムに取得
    print(f"{count}回目")
    print(f"この科目の合計点は{point}点です")

    if point >= 0 and point < 60 :    # 0点以上60点未満
        print("成績はEです\n")
    elif point >= 60 and point < 70 :    # 60点以上70点未満
        print("成績はDです\n")
    elif point >= 70 and point < 80 :    # 70点以上80点未満
        print("成績はBです\n")
    elif point >= 80 and point < 90 :    # 80点以上90点未満
        print("成績はAです\n")
    elif point >= 90 and point <= 100 :    # 90点以上100点以下
        print("成績はSです\n")
    else :   # エラー処理
        print("点数を正しく入力してください\n")
        continue  # 成績処理をしてないものとしてループの先頭へ

    count += 1
    if count == 4 :  # 3回の成績処理を終えたらループから抜ける
        break

print("終了しました")
```

    1回目
    この科目の合計点は11点です
    成績はEです
    
    2回目
    この科目の合計点は58点です
    成績はEです
    
    3回目
    この科目の合計点は61点です
    成績はDです
    
    終了しました
    

### 2.12 リスト

**リスト**は、連続的な複数の情報を管理することができるオブジェクトです。

-  リストに含まれているそれぞれの値を**要素**といい、データを格納できる。
-  リストの各要素には番号がついている。  
この要素の番号を**添え字**（**index**）といい、**0から始まる**決まりになっている。  
`例：要素が5つあるリストでは、5番という添え字の要素はない`


```python
test = []  # 空のリスト
print("type(test) -->", type(test))
```

    type(test) --> <class 'list'>
    

Pythonでは、変数が型を持たないように、リストにも型の定めはありません。  
1つのリストに対して、文字列や数字など、異なるデータ型の値を格納できます。  

``` python
# リストの定義
リスト名 = [<要素1>, <要素2>, ...]

```


```python
# リスト
x = [1, 2, 3]
print("x -->", x)
```

    x --> [1, 2, 3]
    

リストの各要素には、以下の形式でアクセスすることができます。

``` python
# リストへのアクセス
<リスト名>[要素番号]
```


```python
# 要素の参照
x = [1, 2, 3]
print("x[0] -->", x[0])
```

    x[0] --> 1
    

要素を参照するだけではなく、新しい要素を代入することもできます。


```python
# （最初の）要素に代入
x = [1, 2, 3]
x[0] = 10
print("x -->", x)
```

    x --> [10, 2, 3]
    

負の数を指定すると、末尾からの順番で指定することもできます。


```python
# （最後の）要素に代入
x = [1, 2, 3]
x[-1] = 10
print("x -->", x)
```

    x --> [1, 2, 10]
    

「**スライス**」と呼ばれる機能を使うことで、一度に複数要素アクセスすることが可能になります。  


``` python
<リスト名>[開始位置:終了位置:増分]
```

- 開始位置 : デフォルトは先頭
- 終了位置: デフォルトは末尾(の後ろ)
- 増分: デフォルトは1

一部を省略するとデフォルト値が使われます。  
スライスでアクセスしたとき、**終了位置は含まれない**ことに注意してください。


```python
# スライス(参照)
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# リストのスライス機能でリストオブジェクトを複製
list1 = x[1:9:2]
list2 = x[1:4:]
list3 = x[:5:]
list4 = x[3::]
list5 = x[::2]
list6 = x[1::2]
list7 = x[-2::]
list8 = x[::-1]

# スライス結果の表示
print("元リスト", x)
print("[1:9:2] -->", list1)
print("[1:4:] -->", list2)
print("[:5:]  -->", list3)
print("[3::]  -->", list4)
print("[::2]  -->", list5)
print("[1::2] -->", list6)
print("[-2::] -->", list7)
print("[::-1] -->", list8)
```

    元リスト [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    [1:9:2] --> [2, 4, 6, 8]
    [1:4:] --> [2, 3, 4]
    [:5:]  --> [1, 2, 3, 4, 5]
    [3::]  --> [4, 5, 6, 7, 8, 9, 10]
    [::2]  --> [1, 3, 5, 7, 9]
    [1::2] --> [2, 4, 6, 8, 10]
    [-2::] --> [9, 10]
    [::-1] --> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
    

スライスは文字列型のオブジェクトに対しても適用することができます。


```python
# 文字列"stressed"の文字を逆に並べる
str1 = "stressed"
print("str1 -->", str1)

ans1 = str1[::-1]
print("str1[::-1] -->", ans1)

# 文字列の1,3,5,7文字目を取り出して連結する
str2 = "パタトクカシーー"
print("str2 -->", str2)

ans2 = str2[::2]
print("str2[::2] -->", ans2)
```

    str1 --> stressed
    str1[::-1] --> desserts
    str2 --> パタトクカシーー
    str2[::2] --> パトカー
    

以下、リストに適用できる関数・メソッドの一部になります。


```python
x = [1, 2, 3, 4, 5]
print(f"元リスト：{x}")

# リストの長さ
print(f"len(x) --> {len(x)}")

# リスト内の数値の合計
print(f"sum(x) --> {sum(x)}")

# リスト内の数値の平均
print(f"average --> {sum(x)/len(x)}")

# リスト内の最大値
print(f"max --> {max(x)}")

# リスト内の最小値
print(f"min --> {min(x)}")
```

    元リスト：[1, 2, 3, 4, 5]
    len(x) --> 5
    sum(x) --> 15
    average --> 3.0
    max --> 5
    min --> 1
    


```python
x = [1, 2, 3, 4, 5]
print(f"元リスト：{x}")

# リストの繰り返し
print(f"x*3 --> {x*3}")

# リストに要素が含まれているか調べる
print(f"3 in x --> {3 in x}")

# 要素のインデックスを調べる
print(f"x.index(3) --> {x.index(3)}")

# 要素の個数を調べる
print(f"x.count(3) --> {x.count(3)}")
```

    元リスト：[1, 2, 3, 4, 5]
    x*3 --> [1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
    3 in x --> True
    x.index(3) --> 2
    x.count(3) --> 1
    


```python
# 要素の追加（リストの末尾）
x = [1, 2, 3, 4, 5]
print(f"元リスト：{x}")
x.append(6)
print(f"append(6) --> {x}")

print("------------------------------")

# 要素の追加（場所指定）
# リスト名.insert(挿入先要素番号, 参照するオブジェクト)
print(f"元リスト：{x}")
x = [1, 2, 3, 4, 5]
x.insert(2, 2.5)
print(f"insert(2, 2.5) --> {x}")
```

    元リスト：[1, 2, 3, 4, 5]
    append(6) --> [1, 2, 3, 4, 5, 6]
    ------------------------------
    元リスト：[1, 2, 3, 4, 5, 6]
    insert(2, 2.5) --> [1, 2, 2.5, 3, 4, 5]
    


```python
# 要素の削除（要素番号指定）
x = [1, 2, 3, 4, 5]
print(f"元リスト：{x}")
x.pop(3)
print(f"pop(3) --> {x}")

# 要素の削除（引数がないときは最後の要素）
x = [1, 2, 3, 4, 5]
print(f"元リスト：{x}")
x.pop()
print(f"pop() --> {x}")

print("------------------------------")

# 要素の削除（オブジェクト指定）
# 最初にヒットした方だけ削除される
x = [1, 2, 3, 4, 5, 3]
print(f"元リスト：{x}")
x.remove(3)
print(f"remove(3) --> {x}")

print("------------------------------")

# リスト内の要素を全削除
x = [1, 2, 3, 4, 5]
print(f"元リスト：{x}")
x.clear()
print(f"clear() --> {x}")
```

    元リスト：[1, 2, 3, 4, 5]
    pop(3) --> [1, 2, 3, 5]
    元リスト：[1, 2, 3, 4, 5]
    pop() --> [1, 2, 3, 4]
    ------------------------------
    元リスト：[1, 2, 3, 4, 5, 3]
    remove(3) --> [1, 2, 4, 5, 3]
    ------------------------------
    元リスト：[1, 2, 3, 4, 5]
    clear() --> []
    


```python
weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
print(f"元リスト：{weekdays}")

# sortメソッド
# リストオブジェクトの中身を直接並び替え

# ソートによる昇順並び替え
weekdays.sort()
print(f"sort() --> {weekdays}")

# ソートによる降順並び替え
weekdays.sort(reverse=True)
print(f"sort(reverse=True) --> {weekdays}")

print("------------------------------")

weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
print(f"元リスト：{weekdays}")

# sorted関数
# 別のリストオブジェクトを生成

# ソートによる昇順並び替え
week_1 = sorted(weekdays)
print(f"sorted(weekdays) --> {week_1}")

# ソートによる降順並び替え
week_2 = sorted(weekdays, reverse=True)
print(f"sorted(weekdays, reverse=True) --> {week_2}")

# リストの中に数値や文字列が混在していた場合は、並び替えはできない

print("------------------------------")

weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
print(f"元リスト：{weekdays}")

# reverseメソッド
# リストの要素の反転
weekdays.reverse()
print(f"weekdays.reverse() --> {weekdays}")

weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]

# reversed関数
# リストの要素の反転
week_3 = list(reversed(weekdays))
print(f"reversed(weekdays) --> {week_3}")
```

    元リスト：['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
    sort() --> ['Friday', 'Monday', 'Thursday', 'Tuesday', 'Wednesday']
    sort(reverse=True) --> ['Wednesday', 'Tuesday', 'Thursday', 'Monday', 'Friday']
    ------------------------------
    元リスト：['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
    sorted(weekdays) --> ['Friday', 'Monday', 'Thursday', 'Tuesday', 'Wednesday']
    sorted(weekdays, reverse=True) --> ['Wednesday', 'Tuesday', 'Thursday', 'Monday', 'Friday']
    ------------------------------
    元リスト：['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
    weekdays.reverse() --> ['Friday', 'Thursday', 'Wednesday', 'Tuesday', 'Monday']
    reversed(weekdays) --> ['Friday', 'Thursday', 'Wednesday', 'Tuesday', 'Monday']
    


```python
# リストの複製（ダメな例）
x = [1, 2, 3, 4, 5]
x2 = x                            # オブジェクトIDの代入
print(f"before:{x}\nafter:{x2}")  # 複製できているように見えるが…

x2.remove(3)
print(f"before:{x}\nafter:{x2}")  # 元のリストまで変わってしまう

print("------------------------------")

# copyメソッド
# リストの複製（OKな例）
x = [1, 2, 3, 4, 5]
x2 = x.copy()
print(f"before:{x}\nafter:{x2}")  # 複製できているように見える

x2.remove(3)
print(f"before:{x}\nafter:{x2}")  # 元のリストは変化しない

print("------------------------------")

# list関数
# リストの複製（OKな例）
x = [1, 2, 3, 4, 5]
x2 = list(x)
print(f"before:{x}\nafter:{x2}")  # 複製できているように見える

x2.remove(3)
print(f"before:{x}\nafter:{x2}")  # 元のリストは変化しない
```

    before:[1, 2, 3, 4, 5]
    after:[1, 2, 3, 4, 5]
    before:[1, 2, 4, 5]
    after:[1, 2, 4, 5]
    ------------------------------
    before:[1, 2, 3, 4, 5]
    after:[1, 2, 3, 4, 5]
    before:[1, 2, 3, 4, 5]
    after:[1, 2, 4, 5]
    ------------------------------
    before:[1, 2, 3, 4, 5]
    after:[1, 2, 3, 4, 5]
    before:[1, 2, 3, 4, 5]
    after:[1, 2, 4, 5]
    


```python
# リストの結合
weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
weekends = ["Saturday", "Sunday"]
print(f"weekdays:{weekdays}")
print(f"weekends:{weekends}")

print("------------------------------")

# "+"演算子
week = weekdays + weekends
print(f"week:{week}")

print("------------------------------")

# extendメソッド
# 結合したいリストを引数に取る
weekdays.extend(weekends)
print(f"week:{weekdays}")
```

    weekdays:['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
    weekends:['Saturday', 'Sunday']
    ------------------------------
    week:['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
    ------------------------------
    week:['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
    


```python
# 文字列のリストを一つの文字列に連結
weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]

print(f"weekdays:{weekdays}")

print("------------------------------")

# joinメソッド
# 結合する際の区切り文字を指定できる
text1 = " ".join(weekdays)  # 空白で文字列を区切る
print(text1)

text2 = "\\".join(weekdays)  # "\"で文字列を区切る
print(text2)
```

    weekdays:['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
    ------------------------------
    Monday Tuesday Wednesday Thursday Friday
    Monday\Tuesday\Wednesday\Thursday\Friday
    

リストを操作するにあたっては、ループを利用することが多いです。


```python
# リスト内の文字列をすべて大文字にするプログラム
weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
print(f"before:{weekdays}")

for i in range(len(weekdays)):
    weekdays[i] = weekdays[i].upper()

print(f"after:{weekdays}")
```

    before:['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
    after:['MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY']
    

**`zip`関数**を使うことで、複数のリストからそれぞれ要素を順番に取得することができます。


```python
weekdays_en = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
weekdays_ja = ["月曜日", "火曜日", "水曜日", "木曜日", "金曜日"]

for en, ja in zip(weekdays_en, weekdays_ja):
    print(en + " " + ja)
```

    Monday 月曜日
    Tuesday 火曜日
    Wednesday 水曜日
    Thursday 木曜日
    Friday 金曜日
    

**`enumerate`関数**を使うことで、繰り返しの回数とともにリストから要素を順番に取得することができます。


```python
weekdays_en = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]

for idx, day in enumerate(weekdays_en):
    print(str(idx) + " " + day)
```

    0 Monday
    1 Tuesday
    2 Wednesday
    3 Thursday
    4 Friday
    

**内包表記**と呼ばれる方法を利用することで、反復処理をシンプルに記述することができます。

``` python
# 内包表記の一般形
[<式> for <要素> in <イテラブル>]
```

``` python
# appendメソッドを使用した一般形
for <要素> in <イテラブル>:
    <リスト名>.append(<式>)
```


```python
# 内包表記を使ったプログラム
s = [i for i in range(10)]
print(s)

# append()を使ったプログラム
s = []
for i in range(10) :
    s.append(i)
print(s)
```

    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    


```python
s = [i for i in range(10)]  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# iの2乗の値を格納
s1 = [i**2 for i in s]
print(s1)

# 偶数のとき、iの2乗の値を格納
s2 = [i**2 for i in s if i % 2 == 0]
print(s2)
```

    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    [0, 4, 16, 36, 64]
    

リストの中にリストを入れた構造は、**2次元リスト**と呼ばれます。  
表の構造を持つデータ管理などに使われます。  


```python
weekdays = [
    ["月", "月曜日", "Monday"],
    ["火", "火曜日", "Tuesday"],
    ["水", "水曜日", "Wednesday"],
    ["木", "木曜日", "Thursday"],
    ["金", "金曜日", "Friday"],
]

# リスト全体を参照
print(f"weekdays --> {weekdays}")

# リストの0番目だけを参照
print(f"weekdays[0] --> {weekdays[0]}")

# リストの1番目の要素をそれぞれ参照
print(f"{weekdays[1][1]}(-->weekdays[1][1])の英語名は{weekdays[1][2]}(-->weekdays[1][2])です")
```

    weekdays --> [['月', '月曜日', 'Monday'], ['火', '火曜日', 'Tuesday'], ['水', '水曜日', 'Wednesday'], ['木', '木曜日', 'Thursday'], ['金', '金曜日', 'Friday']]
    weekdays[0] --> ['月', '月曜日', 'Monday']
    火曜日(-->weekdays[1][1])の英語名はTuesday(-->weekdays[1][2])です
    

### 2.13 タプル

**タプル**は、リストとほぼ同じ特徴を持つオブジェクトです。  
唯一、**「要素の追加・変更・削除ができない」** という点だけが異なります。   

**「タプルで宣言したデータは処理速度がリストより速い」** という点が、  
タプルを使う大きなメリットです。


```python
test = ()  # 空のタプル
print("type(test) -->", type(test))
```

    type(test) --> <class 'tuple'>
    

リストが**同じ種類のデータをまとめる**のに対して、  
タプルは**異なる種類のデータをまとめる**ことが多いです。

``` python
# タプルの定義
タプル名 = (<要素1>, <要素2>, ...)

```


```python
# タプル
x = (1, 2, 3)
print("x -->", x)
```

    x --> (1, 2, 3)
    

タプルの各要素には、以下の形式でアクセスすることができます。

``` python
# タプルへのアクセス
<タプル名>[要素番号]
```


```python
# 要素の参照
x = (1, 2, 3)
print("x[0] -->", x[0])
```

    x[0] --> 1
    

新しい要素を代入しようとするとエラーが発生します。


```python
# （最初の）要素に代入
x = (1, 2, 3)
# x[0] = 10  # エラーが発生
```

タプルで要素数が1となるデータを扱う際は注意が必要です。   
要素数1のタプルを生成するには、タプル定義に記述する値の後ろに**カンマ**をつけます。

``` python
# 要素数1のタプル
<タプル名> = (<要素>,)
```

要素の追加や削除などを除けば、リストと同じメソッドやスライスによる参照を利用することができます。

タプルの複数の要素を1つにまとめることを**パック**といいます。  
また、タプルを展開して複数の変数に1要素ずつ渡すことを**アンパック**といいます。


```python
# タプルのパック
# 3つの要素を一つにまとめて格納
data = ("Japan", "81", 21)
print("data -->", data)

# タプルのアンパック
# 4つの変数に4つの要素を一つずつ渡す
name, number, age = data

# 変数の出力
print(f"name --> {name}")
print(f"number --> {number}")
print(f"age --> {age}")
```

    data --> ('Japan', '81', 21)
    name --> Japan
    number --> 81
    age --> 21
    

タプルのアンパックを行うときには、**変数と代入する値の数が一致している**必要があります。

### 2.14 ディクショナリ

**ディクショナリ**は、それぞれの要素に**キー**という見出し情報を付けて  
データを管理するオブジェクトです。

ディクショナリを利用することで、それぞれのデータが何を意味しているのか分かりやすくなります。


```python
test = {}  # 空のディクショナリ
print("type(test) -->", type(test))
```

    type(test) --> <class 'dict'>
    

**{}**（**波カッコ**）によってディクショナリを生み出し、各要素を **「キー : 値」** の形式で指定します。

``` python
# ディクショナリの定義
<ディクショナリ名> = {<キー1>:<値1>, <キー2>:<値2>, ...}

```


```python
# ディクショナリ
x = {"a": 1, "b": 2, "c": 3}
print("x -->", x)
```

    x --> {'a': 1, 'b': 2, 'c': 3}
    

各要素に付けるキーは、次のようなルールに従って開発者が自由に決定することができます。   
キーには文字列が使われることが多いです。

- キーには、さまざまな型のデータを指定できる。
- キーのデータ型は要素ごとに異なってもよい
- キーの重複も許される（最後に指定したもの以外は無視される）

ディクショナリの各要素には、以下の形式でアクセスすることができます。

``` python
# ディクショナリへのアクセス
<ディクショナリ名>[キー]
```


```python
# 要素の取得
x = {"a": 1, "b": 2, "c": 3}
print('x["a"] -->', x["a"])
```

    x["a"] --> 1
    

**`get`メソッド**を使うことでも、ディクショナリ内の要素を取得できます。


```python
# getメソッド
# 要素の取得
x = {"a": 1, "b": 2, "c": 3}
print('x.get("a") -->', x.get("a"))

# 指定したキーがないと、Noneを返す
# エラーを出したくないときに利用する
print('x.get("d") -->', x.get("d"))
# print('x["d"] -->', x["d"])  # エラー発生
```

    x.get("a") --> 1
    x.get("d") --> None
    

ディクショナリの要素を追加、あるいは変更したい場合は、  
以下の形式を利用します。

``` python
# 要素の追加
<ディクショナリ名>[新しいキー] = <新しい値>
```

``` python
# 要素の変更
<ディクショナリ名>[変更したい要素のキー] = <変更後の値>
```


```python
# 要素の追加と変更
x = {"a": 1, "b": 2, "c": 3}
print('before -->', x)

x["d"] = 4  # ディクショナリに要素を追加
x["a"] = 0  # ディクショナリの要素を変更

print('after -->', x)
```

    before --> {'a': 1, 'b': 2, 'c': 3}
    after --> {'a': 0, 'b': 2, 'c': 3, 'd': 4}
    


```python

```

ディクショナリの要素を削除するには、**del文**という特殊な構文を用います。

``` python
# 要素の削除
del <ディクショナリ名>[削除したい値のキー]
```


```python
# 要素の追加と変更
x = {"a": 1, "b": 2, "c": 3}
print('before -->', x)

del x["c"]  # ディクショナリの要素を削除

print('after -->', x)
```

    before --> {'a': 1, 'b': 2, 'c': 3}
    after --> {'a': 1, 'b': 2}
    

ディクショナリに入っているキーをすべて取得するには、**`keys`メソッド**を使います。


```python
x = {"a": 1, "b": 2, "c": 3}
print('x -->', x)

# キーをすべて取得
print('list(x.keys()) -->', list(x.keys()))

# 辞書に入っているkeyをfor文で取り出す
for key in x.keys():
    print(key)
```

    x --> {'a': 1, 'b': 2, 'c': 3}
    list(x.keys()) --> ['a', 'b', 'c']
    a
    b
    c
    

値をすべて取得したいときには、**`values`メソッド**を使います。


```python
x = {"a": 1, "b": 2, "c": 3}
print('x -->', x)

# 値をすべて取得
print('list(x.values()) -->', list(x.values()))

# 辞書に入っているvalueをfor文で取り出す
for value in x.values():
    print(value)
```

    x --> {'a': 1, 'b': 2, 'c': 3}
    list(x.values()) --> [1, 2, 3]
    1
    2
    3
    

キーと値を同時に取得したいときには、**`items`メソッド**を使います。  


```python
x = {"a": 1, "b": 2, "c": 3}
print('x -->', x)

# キーと値をすべて取得
print('list(x.items()) -->', list(x.items()))

# 辞書に入っているkeyとvalueをfor文で取り出す
for key, value in x.items():
    print(key, value)
```

    x --> {'a': 1, 'b': 2, 'c': 3}
    list(x.items()) --> [('a', 1), ('b', 2), ('c', 3)]
    a 1
    b 2
    c 3
    

`items`メソッドで取得したキーと値を、`sorted`関数の引数に渡すことで、  
ディクショナリを"キー"でソートすることができます。


```python
fruits_dict = {'Banana': 200, 'Lemon': 150, 'Apple': 120, 'Grape': 300}
print('fruits_dict -->', fruits_dict)
# {'Banana': 200, 'Lemon': 150, 'Apple': 120, 'Grape': 300}

# ディクショナリをキーでソート
fruits_dict = dict(sorted(fruits_dict.items()))

print("sorted(fruits_dict.items())で更新")
print('fruits_dict -->', fruits_dict)
# {'Apple': 120, 'Banana': 200, 'Grape': 300, 'Lemon': 150}

```

    fruits_dict --> {'Banana': 200, 'Lemon': 150, 'Apple': 120, 'Grape': 300}
    dict(sorted(fruits_dict.items()))で更新
    fruits_dict --> {'Apple': 120, 'Banana': 200, 'Grape': 300, 'Lemon': 150}
    

`sorted`関数の`key`に、辞書の値を渡すことで、   
ディクショナリを"値"でソートすることができます。


```python
fruits_dict = {'Banana': 200, 'Lemon': 150, 'Apple': 120, 'Grape': 300}
print('fruits_dict -->', fruits_dict)
# {'Banana': 200, 'Lemon': 150, 'Apple': 120, 'Grape': 300}

# ディクショナリを値でソート
fruits_dict = dict(sorted(fruits_dict.items(), key = lambda fruit : fruit[1]))

print("sorted(fruits_dict.items(), key = lambda fruit : fruit[1])で更新")
print('fruits_dict -->', fruits_dict)
# {'Apple': 120, 'Lemon': 150, 'Banana': 200, 'Grape': 300}

```

    fruits_dict --> {'Banana': 200, 'Lemon': 150, 'Apple': 120, 'Grape': 300}
    dict(sorted(fruits_dict.items(), key = lambda fruit : fruit[1]))で更新
    fruits_dict --> {'Apple': 120, 'Lemon': 150, 'Banana': 200, 'Grape': 300}
    

任意の順番でソートすることもできます。


```python
fruits_dict = {'Banana': 200, 'Lemon': 150, 'Apple': 120, 'Grape': 300}
print('fruits_dict -->', fruits_dict)
# {'Banana': 200, 'Lemon': 150, 'Apple': 120, 'Grape': 300}

# ディクショナリを任意の順番でソート
fruit_order = ['Apple', 'Banana', 'Lemon', 'Grape']
fruits_dict = dict(sorted(fruits_dict.items(), key=lambda x: fruit_order.index(x[0])))

print("sorted(fruits_dict.items(), key=lambda x: fruit_order.index(x[0]))で更新")
print('fruits_dict -->', fruits_dict)
# {'Apple': 120, 'Banana': 200, 'Lemon': 150, 'Grape': 300}

```

    fruits_dict --> {'Banana': 200, 'Lemon': 150, 'Apple': 120, 'Grape': 300}
    sorted(fruits_dict.items(), key=lambda x: fruit_order.index(x[0]))で更新
    fruits_dict --> {'Apple': 120, 'Banana': 200, 'Lemon': 150, 'Grape': 300}
    

### 2.15 セット

**セット**は、集合を表すオブジェクトです。

重複しない要素を管理することができるオブジェクトで、集合演算を行うことができます。


```python
test = set()  # 空のセット
print("type(test) -->", type(test))
```

    type(test) --> <class 'set'>
    

順番を考慮しないのが、セットオブジェクトの特徴です。  
つまり、順序は関係なく、データを集合として管理したいという用途に使います。

``` python
# セットの定義
セット名 = {<要素1>, <要素2>, ...}

```

大きな特徴は以下の4点です。

① 重複した値を格納することができない  
② 添え字やキーという概念がなく、特定の要素に対して代入・参照する方法が存在しない  
③ 添え字がないため、要素が順序を持たない  
④ `append`メソッドの代わりに **`add`メソッド** で要素を追加する


```python
# セットの作成
x = {2, 3, 3, 4, 5, 7, 9}

# セットの表示（重複が削除される）
print("x -->", x)  # {2, 3, 4, 5, 7, 9}

```

    x --> {2, 3, 4, 5, 7, 9}
    

作成したセットに要素を追加するには、**`add`メソッド**を使います。  



```python
x = {1, 2, 3 ,4 ,5}
print("x -->", x)

x.add(6)
print("x.add(6) -->", x)  # 要素の追加

x.add(1)
print("x.add(1) -->", x)  # 同じオブジェクトを追加しても、特に変化しない
```

    x --> {1, 2, 3, 4, 5}
    x.add(6) --> {1, 2, 3, 4, 5, 6}
    x.add(1) --> {1, 2, 3, 4, 5, 6}
    

**`remove`メソッド**を使うと、オブジェクトを指定して要素を削除できます。


```python
x = {1, 2, 3 ,4 ,5}
print("x -->", x)

x.remove(3)
print("x.remove(3) -->", x)  # 要素の削除
```

    x --> {1, 2, 3, 4, 5}
    x.remove(3) --> {1, 2, 4, 5}
    

セットとリスト・タプルは、相互変換されることが多いです。


```python
# リストとタプルの定義
list1 = [10, 20, 30, 40, 50]
tuple1 = ("A", "B", "C")
print("list1 -->", list1)
print("tuple1 -->", tuple1)

# 「リスト」と「タプル」から「セット」を生成
print("set(list1) -->", set(list1))
print("set(tuple1) -->", set(tuple1))
```

    list1 --> [10, 20, 30, 40, 50]
    tuple1 --> ('A', 'B', 'C')
    set(list1) --> {40, 10, 50, 20, 30}
    set(tuple1) --> {'C', 'B', 'A'}
    


```python
# セットの定義
set1 = {10, 20, 30, 40, 50}
print("set1 -->", set1)

# 「セット」から「リスト」と「タプル」を生成
print("list(set1) -->", list(set1))
print("tuple(set1) -->", tuple(set1))
```

    set1 --> {50, 20, 40, 10, 30}
    list(set1) --> [50, 20, 40, 10, 30]
    tuple(set1) --> (50, 20, 40, 10, 30)
    

Pythonでは、これら集合の関係性を演算で簡単に作り出すことができます。


```python
set1 = {1, 2, 3, 4, 5}
set2 = {1, 3, 5, 7, 9}
print("set1 -->", set1)
print("set2 -->", set2)

# セットの和集合
# 複数の集合に含まれる全ての要素で構成される集合
print("set1 | set2 -->", set1 | set2)

# セットの差集合
# ある集合に含まれるが、他の集合には含まれないものを要素とする集合
print("set1 - set2 -->", set1 - set2)

# セットの積集合
# 複数の集合に共通する要素で構成される集合
print("set1 & set2 -->", set1 & set2)

# セットの対象差
# それぞれの集合のみに存在する要素で 構成される集合
print("set1 ^ set2 -->", set1 ^ set2)
```

    set1 --> {1, 2, 3, 4, 5}
    set2 --> {1, 3, 5, 7, 9}
    set1 | set2 --> {1, 2, 3, 4, 5, 7, 9}
    set1 - set2 --> {2, 4}
    set1 & set2 --> {1, 3, 5}
    set1 ^ set2 --> {2, 4, 7, 9}
    

### 2.16 コレクションまとめ

関連するデータをまとめて1つの変数として扱う仕組みを、  
Pythonでは**コレクション**と呼びます。

コレクションには、リスト、タプル、セット、辞書などが含まれます。  
**イテラブル**（要素を順番に取り出すことができるオブジェクト）となります。

コレクションは、主に**イテラブル**は、要素を順番に取り出すことができるオブジェクトのことです。



変更可能なオブジェクトを **「ミュータブル」**、  
変更不可能なオブジェクトを **「イミュータブル」** といいます。

リスト、ディクショナリ、セットはミュータブルです。  
タプル、数値、文字列、booleanはイミュータブルです。

コレクションの中に別のコレクションを格納することもできます。  
多重構造のことを**ネスト**や**入れ子**といいます。


```python
# ディクショナリの中にディクショナリを入れた二重構造

schedule = {
    "weekdays": {"月曜日": "Monday", "火曜日": "Tuesday", "水曜日": "Wednesday", "木曜日": "Thursday", "金曜日": "Friday"},
    "weekends": {"土曜日": "Saturday", "日曜日": "Sunday"},
}


print('schedule["weekdays"]["月曜日"] -->', schedule["weekdays"]["月曜日"])
print('schedule["weekends"]["土曜日"] -->', schedule["weekends"]["土曜日"])
```

    schedule["weekdays"]["月曜日"] --> Monday
    schedule["weekends"]["土曜日"] --> Saturday
    

### 2.17 組み込み関数

**関数**は、与えられた入力データに対して特定の操作や手続きを行い、  
その結果を返す手順の集まりです。

一般的に、関数は定義された処理を実行するために呼び出されます。

Pythonにおける関数は、**独自関数**または**標準関数**（**組み込み関数**）のいずれかです。

Pythonで最初から準備されている関数のことを、**組み込み関数**といいます。

``` python
# 組み込み関数の例
enumerate()
format()
id()
input()
len()
print()
range()
sorted()
sum()
type()
```

他にも以下のような関数があります。


```python
# abs関数
# 引数の絶対値を返す
print('abs(-10) -->', abs(-10))

# divmod関数
# 引数に指定した2つの数値の商と余りをタプルとして返す
# 一度に商と余りを求めることができる
print('divmod(7, 4) -->',  divmod(7, 4))

# pow関数
# 第一引数(数値)を第二引数(数値)乗した結果を返す
# **演算子よりも高速に計算できる
print('pow(7, 3) -->',  pow(7, 3))
```

    abs(-10) --> 10
    divmod(7, 4) --> (1, 3)
    pow(7, 3) --> 343
    


```python
# all関数
# 引数の全要素がTrueならば、Trueを返す
print('all([True, True]) -->', all([True, True]))
print('all([True, False]) -->', all([True, False]))

# any関数
# 引数のいずれかの要素がTrueならば、Trueを返す
print('any([True, True]) -->', any([True, True]))
print('any([True, False]) -->', any([True, False]))
```

    all([True, True]) --> True
    all([True, False]) --> False
    any([True, True]) --> True
    any([True, False]) --> True
    


```python
number = 81   # 10進数（整数）
print('number -->', number)

bin_number = bin(number) # 2進数に変換
oct_number = oct(number) # 8進数に変換
hex_number = hex(number) # 16進数に変換

print('bin_number -->', bin_number)
print('oct_number -->', oct_number)
print('hex_number -->', hex_number)

print("------------------------------")

hex_number = "FF"   # 16進数
print('hex_number -->', hex_number)

number = int(hex_number, 16) # 10進数に変換
bin_number = bin(number) # 2進数に変換
oct_number = oct(number) # 8進数に変換

print('number -->', number)
print('bin_number -->', bin_number)
print('oct_number -->', oct_number)
```

    number --> 81
    bin_number --> 0b1010001
    oct_number --> 0o121
    hex_number --> 0x51
    ------------------------------
    hex_number --> FF
    number --> 255
    bin_number --> 0b11111111
    oct_number --> 0o377
    

### 2.18 独自関数

組み込み関数とは別に、関数は自分で作ることもできます（**独自関数**）。  

関数を自分で作れるようになると、プログラムを複数の部品に分けることができるようになります。  
1つのプログラムを複数の部品に分けることを**部品化**といいます。メリットは以下の通りです。  

- プログラム全体の見通しがよくなり、処理を把握しやすくなる
- 機能ごとに関数を記述するため、修正範囲を限定できる
- 何度も使う機能を関数にまとめることで、プログラミングの作業効率が上がる

関数を利用するには、**定義**と**呼び出し**の2ステップが必要です。

```python
# 関数定義
def <関数名>(<引数>, ...):
    <関数内部の処理>
```

```python
# 関数呼び出し
<関数名>(<引数>, ...)
```



関数を呼び出す際に、0個以上の**引数**を渡します。  
そして、関数内部ではこれらの引数の値を利用して処理を行います。


関数を呼び出す際、指定する引数の個数は  
関数が定義されたときの引数の個数と一致する必要があります。


```python
# 絶対値を求めるプログラム（関数未定義）
x = -10
if (x < 0):
    y = - x
else:
    y = x
print('x -->', x)
print('y -->', y)
```

    x --> -10
    y --> 10
    


```python
# 絶対値を求める関数の定義
def absolute(x):
    if (x < 0):
        y = - x
    else:
        y = x
    return y

# 絶対値を求める関数の呼び出し
x = -10
absolute(x)
print('x -->', x)
print('absolute(x) -->', absolute(x))
```

    x --> -10
    absolute(x) --> 10
    


プログラミングでは、関数を定義する際に指定した引数を「**仮引数**」と呼びます。  
一方、関数を呼び出す際に渡す引数を「**実引数**」と呼びます。

関数が評価されて返される値を「**戻り値**」と言います。  
戻り値は通常、関数内で **`return`文** で指定された値ですが、`return`がない場合は`None`になります。


```python
# 文字列を指定された回数だけ連続して表示する関数
def print_word_multiple_times(word, count):
    """
    word (str): 表示する文字列
    count (int): 表示する回数
    """
    for _ in range(count):
        print(word)

# 関数の使用例
print_word_multiple_times("Hello", 3)

```

    Hello
    Hello
    Hello
    

仮引数と実引数の対応を明示的に指定する場合には、以下の形式で指定します。

``` python
<関数名>(<仮引数>=<実引数>, ...)
```

この形式で渡す引数を**キーワード引数**と言います。


```python
# キーワード引数の使用例
print_word_multiple_times(word="Hello", count=3)
```

    Hello
    Hello
    Hello
    

引数(の一部)に既定値を与えておき、その引数を省略可能とすることもできます。  
以下の形式で指定します。

``` python
def <関数名>(<引数>=<デフォルト引数>, ...):
    <関数内部の処理>
```
これを**デフォルト引数**と言います。  
関数呼び出しの際にその引数が省略された場合、既定値が使用されます。


```python
# 文字列を指定された回数だけ連続して表示する関数
# デフォルト引数を定義
def print_word_multiple_times(word="Hello", count=3):
    """
    word (str): 表示する文字列
    count (int): 表示する回数
    """
    for _ in range(count):
        print(word)

# キーワード引数の使用例
# 変数countは省略
print_word_multiple_times(word="Hello World!")

```

    Hello World!
    Hello World!
    Hello World!
    

**可変長引数**とは、関数の引数の個数を指定せずに引数を渡す方法です。  

仮引数に可変長引数`*args`を使うと、任意の個数の位置引数を**タプル**にまとめて  
その仮引数にセットします。


```python
# 「.png」のファイル名だけをリストで返す
# 可変長引数を用いない場合

def return_png(filename1, filename2):
    png_list = []

    if filename1[-4:] == ".png":
        png_list.append(filename1)

    if filename2[-4:] == ".png":
        png_list.append(filename2)

    return png_list

print(return_png(filename1="image1.png", filename2="image2.jpg"))
```

    ['image1.png']
    

**可変長引数`*args`** を用いることで、仮引数の数やデータ型（リストにするなど）に  
気を使わなくて済むようになります。


```python
# 「.png」のファイル名だけをリストで返す
# 可変長引数を用いる場合

def return_png(*args):
    """
    args = ["image1.png", "image2.jpg"]
    """
    png_list = []

    for filename in args:
      if filename[-4:] == ".png":
          png_list.append(filename)

    return png_list

print(return_png("image1.png", "image2.jpg"))
```

    ['image1.png']
    

仮引数に可変長引数 `**kwargs`を使うと、キーワード引数を1個の辞書にまとめることができます。  
引数の名前は辞書のキー、引数の値は辞書の値になります。  



```python
def print_country_codes(**kwargs):
  """
  kwargs = {'Banana': 200, 'Lemon': 150, 'Apple': 120, 'Grape': 300}
  """

  for country in kwargs:
    print(f"{country}の値段は{kwargs[country]}円です")

print_country_codes(Banana=200, Lemon=150, Apple=120, Grape=300)
```

    Bananaの値段は200円です
    Lemonの値段は150円です
    Appleの値段は120円です
    Grapeの値段は300円です
    

### 2.19 無名関数

Pythonでは、名前を持たない無名関数を作成することができます。

これを**lambda関数**（ラムダ関数と読む）と呼びます。

def文による関数定義とそれに相当するlambdaでの無名関数の対応関係は以下の通りです。

``` python
# defによる関数定義
def <関数名>(<引数>, ...):
    <関数内部の処理>
```

``` python
# lambdaによる関数定義
lambda <引数>, ... : <関数内部の処理>
```

**`def`、関数名、`return`、改行、カッコ**の5つを取ればlambda関数の完成です。


```python
# 整数かどうか判定する関数(def)
def check_number_type(num):
    if isinstance(num, int):
        return "整数"
    else:
        return "実数"

# 関数の使用例
print('10 -->', check_number_type(10))      # Output: 整数
print('3.14 -->', check_number_type(3.14))  # Output: 実数
```

    10 --> 整数
    3.14 --> 実数
    


```python
# 整数かどうか判定する関数(lambda)
check_number_type_lambda = lambda num: "整数" if isinstance(num, int) else "実数"

# 関数の使用例
print('10 -->', check_number_type_lambda(10))      # Output: 整数
print('3.14 -->', check_number_type_lambda(3.14))  # Output: 実数
```

    10 --> 整数
    3.14 --> 実数
    

lambda関数は、一部の関数・メソッドと一緒に用いることが多いです。  

PandasのDataframeとも相性が良いです。参考記事は[こちら](https://www.salesanalytics.co.jp/datascience/datascience207/)。


```python
# sorted関数

fruits_dict = {'Banana': 200, 'Lemon': 150, 'Apple': 120, 'Grape': 300}
print('fruits_dict -->', fruits_dict)
# {'Banana': 200, 'Lemon': 150, 'Apple': 120, 'Grape': 300}

# ディクショナリを値でソート
fruits_dict = dict(sorted(fruits_dict.items(), key = lambda fruit : fruit[1]))

print("sorted(fruits_dict.items(), key = lambda fruit : fruit[1])で更新")
print('fruits_dict -->', fruits_dict)
# {'Apple': 120, 'Lemon': 150, 'Banana': 200, 'Grape': 300}

```


```python
# split()メソッド
get_path = lambda path: path.split('/')

# ファイルのpathを表示
print(get_path('/home/user/Desktop/image.jpg'))
# ファイル名を表示
print(get_path('/home/user/Desktop/image.jpg')[-1])
```

    ['', 'home', 'user', 'Desktop', 'image.jpg']
    image.jpg
    


```python
# map関数
# イテラブルのすべての要素に関数の処理を適用できる

before_list = [1, 2, 3, 4, 5]
print('before_list -->', before_list)

after_list = map(lambda n:n*n , before_list)  # 引数の中でlambda
print('after_list -->', list(after_list))     # リスト型に変換して出力
```

    before_list --> [1, 2, 3, 4, 5]
    after_list --> [1, 4, 9, 16, 25]
    


```python
# filter関数
# イテラブルから、条件に当てはまる要素を抽出できる
# 第一引数に抽出条件を設定した関数を指定する

scores = [58, 89, 62, 50, 78]
print('before_list -->', before_list)


passed_scores = filter(lambda n: n >= 60, scores)  # 引数の中でlambda
print('passed_scores -->', list(passed_scores))    # リスト型に変換して出力
```

    before_list --> [1, 2, 3, 4, 5]
    passed_scores --> [89, 62, 78]
    

### 2.20 ローカル変数とグローバル変数

関数内で準備された変数（**ローカル変数**）は、その関数の中でしか読み書きできません。  
このようなローカル変数の性質を**独立性**といいます。


```python
# 変数greetはローカル変数

def hello():
  greet = "Hello"
  print('greet -->', greet)

hello()
# print(greet)  # 変数greetは利用できない
```

    greet --> Hello
    

どの関数にも属さない場所で定義された変数を、ローカル変数に対し**グローバル変数**といいます。  
**すべての関数から参照してデータを利用することができます。**  
※同名のローカル変数がある場合は、ローカル変数が優先して利用されます。


```python
# 変数greetはグローバル変数

greet = "Hello"

def hello():
  print('greet -->', greet)

hello()
```

    greet --> Hello
    

関数内でグローバル変数を定義する際には、**`global`キーワード**を使用します。

これによって、関数内での変数の参照や代入が  
グローバルスコープの変数に対して行われることを示します。


```python
# 変数greetはglobalキーワード

greet = "Hello"

def hello():
  global greet  # 関数内でグローバル変数xを使用することを示す

  greet = "Hello World!"
  print('greet -->', greet)

hello()
```

    greet --> Hello World!
    

## 3 Python文法(発展)

### 3.1 モジュールとライブラリ


Pythonでは、他の開発者が用意してくれた変数や関数、クラスを  
自由に自分のプログラムに取り入れることができます。  



**モジュール**は、別のプログラムに取り込んで使うことを前提として、  
ある機能をひとまとめにした1つのファイルを指す言葉です。  
関連した機能ごとに、変数や関数などの細かな部品を集めた1つの大きな部品と捉えることができます。

モジュールを複数まとめたものを**パッケージ**と言い、さらにパッケージをまとめたものを**ライブラリ**と言います。
モジュールは、開発した人によって2種類のライブラリに属しています。

**標準ライブラリ**とは、Pythonが公式に用意したモジュールのまとまりです。  
各モジュールには、特定の用途ごとに役立つ変数や関数、クラスが定義されています。

|モジュール|用途|
|:---| :--- |
|mathモジュール|数学計算に関する処理|
|randomモジュール|乱数に関する処理|
|csvモジュール|CSVファイルに関する処理|
|jsonモジュール|JSONファイルに関する処理|
|osモジュール|OS操作に関する処理|

目的に合ったモジュールを取り込んで、定義されている関数などを利用することで、  
専門的な知識がなくても高度な処理を実現することができるようになります。  


Pythonではimportすることでモジュールを読み込むことができます。

``` python
# モジュールの取り込み
import <モジュール名>
```

importすると、そのプログラムファイルで定義された変数・関数・クラスを利用することができます。  
importしていないものは利用することができません。

``` python
# モジュールが持つ変数・関数・クラスの呼び出し
<モジュール名>.<変数名/関数名/クラス名>
```


```python
# mathモジュールの利用
import math

# 変数pi（円周率）を参照
print("円周率は{}です".format(math.pi))

# floor関数(小数点以下で切り捨て)を参照
print("小数点以下を切り捨てれば{}です".format(math.floor(math.pi)))

# ceil関数(小数点以下で切り上げ)を参照
print("小数点以下を切り上げれば{}です".format(math.ceil(math.pi)))
```

    円周率は3.141592653589793です
    小数点以下を切り捨てれば3です
    小数点以下を切り上げれば4です
    

組み込んだモジュールに別の名前を付けることもできます。

``` python
# 別名を付けたモジュールの利用
import モジュール名 as 別名
```


```python
# mathモジュールをmとしてインポートする
import math as m

# 円周率を表示する
print("円周率は{}です".format(m.pi))

# 小数点以下を切り捨てた値を表示する
print("小数点以下を切り捨てれば{}です".format(m.floor(m.pi)))

# 小数点以下を切り上げた値を表示する
print("小数点以下を切り上げれば{}です".format(m.ceil(m.pi)))
```

    円周率は3.141592653589793です
    小数点以下を切り捨てれば3です
    小数点以下を切り上げれば4です
    

モジュール全体ではなく、モジュールから特定の変数や関数だけを取り込むこともできます。

``` python
# 特定の変数・関数・クラスのみを取り込む
from <モジュール名> import <変数名/関数名/クラス名>
```

モジュールと同様に、`as`を使用して取り込んだ変数・関数・クラスに別名を付けることができます。

``` python
# 特定の変数・関数・クラスを別名で取り込む
from <モジュール名> import <変数名/関数名/クラス名>
```

別名を付けることによって名前の重複を避けることができますが、  
別名があまりにも多すぎると逆に混乱することがあるので注意が必要です。


```python
# mathモジュールから円周率(pi)をcircle_ratioという別名でインポートする
from math import pi as circle_ratio

# mathモジュールからfloor関数をround_downという別名でインポートする
from math import floor as round_down

# 円周率を表示する
print("円周率は{}です".format(circle_ratio))

# 小数点以下を切り捨てた値を表示する
print("小数点以下を切り捨てれば{}です".format(round_down(circle_ratio)))
```

    円周率は3.141592653589793です
    小数点以下を切り捨てれば3です
    

import文は、一般的にはプログラムの先頭にまとめて書くことが推奨されています。  
取り込んでいる変数・関数・クラスを把握しやすくするためです。

**外部ライブラリ**とは、Pythonとは別の組織や個人が用意したモジュールのまとまりです。  
膨大な数が存在しますが、その多くは標準ライブラリよりもさらに用途を絞り込んだものとなっています。

外部ライブラリには、標準ライブラリに用意されたモジュールよりも  
高度な処理を行うことができるという特徴があります。  

代表的な外部ライブラリには、以下のようなものがあります。



|モジュール|用途|
|:---| :--- |
|matplotlib|データの可視化|
|seaborn|データの可視化|
|Pandas|データ解析|
|Numpy|ベクトル・行列計算|
|Scipy|科学技術計算|
|scikit-learn|機械学習|
|TensorFlow|深層学習|
|requests|Ｗebアクセス|


今回使っているGoogle Colaboratoryでは、よく使われるライブラリが最初から入っています。  

ここでは`seaborn`というライブラリをインポートして、簡単なグラフを表示してみましょう。


```python
import seaborn as sns

iris = sns.load_dataset("iris")
sns.pairplot(iris)
```




    <seaborn.axisgrid.PairGrid at 0x7efddd47d310>




    
![png](https://imgur.com/IjDe3FY.png)
    


今回`seaborn`の別名として`as`で **`sns`**  と指定しました。  
このように、主要なライブラリには、だいたい`as`で指定する名前が決まっています。  

|モジュール|別名|
|:---| :--- |
|matplotlib.pyplot|plt|
|seaborn|sns|
|Pandas|pd|
|Numpy|np|
|scikit-learn|svm|
|TensorFlow|tf|

すべてのライブラリがGoogle Colaboratoryに入っているわけではありません。

導入されていないライブラリを使うには、pipコマンドを用いて、自分でライブラリをインストールします。

``` python
# ライブラリのインストール
pip install <ライブラリ名>
```


```python
# wikipediaライブラリをインストール
# GoogleColabの場合先頭に「!」が必要
! pip install wikipedia
```

    Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/
    Collecting wikipedia
      Downloading wikipedia-1.4.0.tar.gz (27 kB)
      Preparing metadata (setup.py) ... [?25l[?25hdone
    Requirement already satisfied: beautifulsoup4 in /usr/local/lib/python3.8/dist-packages (from wikipedia) (4.6.3)
    Requirement already satisfied: requests<3.0.0,>=2.0.0 in /usr/local/lib/python3.8/dist-packages (from wikipedia) (2.25.1)
    Requirement already satisfied: urllib3<1.27,>=1.21.1 in /usr/local/lib/python3.8/dist-packages (from requests<3.0.0,>=2.0.0->wikipedia) (1.24.3)
    Requirement already satisfied: idna<3,>=2.5 in /usr/local/lib/python3.8/dist-packages (from requests<3.0.0,>=2.0.0->wikipedia) (2.10)
    Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.8/dist-packages (from requests<3.0.0,>=2.0.0->wikipedia) (2022.12.7)
    Requirement already satisfied: chardet<5,>=3.0.2 in /usr/local/lib/python3.8/dist-packages (from requests<3.0.0,>=2.0.0->wikipedia) (4.0.0)
    Building wheels for collected packages: wikipedia
      Building wheel for wikipedia (setup.py) ... [?25l[?25hdone
      Created wheel for wikipedia: filename=wikipedia-1.4.0-py3-none-any.whl size=11695 sha256=9b61e6c1ccfddda21615ecf9ec0155742e560d70e9165f4b0cfa8ce63371d55e
      Stored in directory: /root/.cache/pip/wheels/07/93/05/72c05349177dca2e0ba31a33ba4f7907606f7ddef303517c6a
    Successfully built wikipedia
    Installing collected packages: wikipedia
    Successfully installed wikipedia-1.4.0
    


```python
# wikipediaライブラリをインポート
import wikipedia

wikipedia.set_lang('ja')
wikipedia.search("Python")
```




    ['Python',
     'モンティ・パイソン',
     'IDLE (Python)',
     'KML',
     'Stackless Python',
     'Eric Python IDE',
     'Anaconda (Pythonディストリビューション)',
     'Blender',
     'Ruby',
     'PyQt']




```python
r = wikipedia.page('Python').url
print(r)
```

    https://ja.wikipedia.org/wiki/Python
    

### 3.2 クラス

機能や状態を1つにまとめて**クラス**とし、  
プログラムの内部構造をモノの集まりとしてとらえる考え方を**オブジェクト指向**といいます。

クラスは機能や状態を定義するいわゆる「設計図」です。  
クラスを使うと新しいデータ型を作ることができます。
    
以下の形式で定義できます。

``` python
# クラスの定義
class <クラス名>
    <クラスの処理>
```


```python
# 空のクラス
# 後で機能や属性を追加することが想定されている
class SampleClass:
    pass
```

クラス名の命名規則には**UpperCamelCase**と呼ばれるスタイルを適用します。  
これは単語の先頭を大文字で表記し、単語の間にアンダースコアを使用しない書き方です。

クラスは単なる設計図であり、オブジェクトにはまだなっていません。  
クラスからオブジェクトを作る（実体化する）ことを**インスタンス化**といいます。

``` python
# インスタンス化
<インスタンス> = <クラス名>()
```

クラスから生成されたオブジェクトを、特に**インスタンス**と呼びます。


```python
# 空クラス
class SampleClass:
    pass

sample = SampleClass()  # 実行しても変化はない
```

クラス内で定義される変数を**属性**、  
クラス内で定義される関数を**メソッド**といいます。



メソッドの引数には **`self`** が必要です。

これはクラス自身、すなわち**インスタンス**を指します。  
メソッドを定義する場合、引数には最低限`self`が必要になります。

`self`と書かなくてもいいのですが、Pythonでは慣習として`self`と記述します。


```python
# クラスCountryの定義
class Country:
  def set_data(self, name, number, code):  # メソッドset_dataの定義
    # 属性定義
    self.name = name
    self.number = number
    self.code = code

japan = Country()  # インスタンス化

japan.set_data("Japan", 81, "392")  # メソッドの呼び出し
print("{}の国名コードは{}です".format(japan.name, japan.code))  # 属性の呼び出し
```

    Japanの国名コードは392です
    

インスタンスは複数生成することができます。


```python
japan = Country()  # インスタンス化

japan.set_data("Japan", 81, "392")   # メソッドの呼び出し
print("{}の国名コードは{}です".format(japan.name, japan.code))  # 属性の呼び出し

america = Country()  # インスタンス化

america.set_data("America", 1, "840")  # メソッドの呼び出し
print("{}の国名コードは{}です".format(america.name, america.code))  # 属性の呼び出し
```

    Japanの国名コードは392です
    Americaの国名コードは840です
    

国名とその国番号を出力する`output`メソッドを作成してみましょう。


```python
class Country:
  def set_data(self, name, number, code):
    self.name = name
    self.number = number
    self.code = code

  def output(self):
    print("{}の国名コードは{}です".format(self.name, self.code))

japan = Country()  # インスタンス化

japan.set_data("Japan", 81, "392")  # メソッドの呼び出し
japan.output()  # メソッドの呼び出し
```

    Japanの国名コードは392です
    

クラスをインスタンス化したときに自動的に実行される特殊なメソッドを  
**コンストラクタ**と呼びます。

``` python
def __init__(self, <引数>):
    <処理>
```
インスタンスの作成と属性の設定を同時に行うことができます。  
コンストラクタは呼び出さなくても、インスタンス化時に自動で実行されます。


```python
class Country:
  def __init__(self, name, number, code):
    self.name = name
    self.number = number
    self.code = code

  def output(self):
    print("{}の国名コードは{}です".format(self.name, self.code))

# インスタンス化
# コンストラクタが実行される
japan = Country("Japan", 81, "392")
japan.output()  # メソッドの呼び出し
```

    Japanの国名コードは392です
    

インスタンスに紐づいている変数を**インスタンス変数**といいます。  
インスタンス変数は他のインスタンスからアクセスすることが出ません。

また、インスタンス変数はこれまでと同じ要領で更新することができます。


```python
class Gakka:
  def __init__(self, name, number, code):
    self.name = name      # インスタンス変数
    self.number = number  # インスタンス変数
    self.code = code        # インスタンス変数

japan = Country("Japan", 81, "392")
print("{}の国名コードは{}です".format(japan.name, japan.code))  # 更新前

japan.code = "JPN"  # インスタンス変数の更新

print("{}の国名コードは{}です".format(japan.name, japan.code))  # 更新後
```

    Japanの国名コードは392です
    Japanの国名コードはJPNです
    

インスタンスに紐づいていない変数を**クラス変数**といいます。

お互いに同じクラスからインスタンス化されたインスタンスであれば、  
他のインスタンスからクラス変数にアクセスすることができます。


```python
import time

class Country:
    now_year = time.localtime().tm_year  # クラス変数

    def __init__(self, name, number, code):
        self.name = name      # インスタンス変数
        self.number = number  # インスタンス変数
        self.code = code      # インスタンス変数
```


```python
japan = Country("Japan", 81, "392")
print("{}は{}年に存在する国です" .format(japan.name, japan.now_year))
print("{}の国名コードは{}です" .format(japan.name, japan.code))

america = Country("America", 1, "840")
print("{}は{}年に存在する国です" .format(america.name, america.now_year))
print("{}の国名コードは{}です" .format(america.name, america.code))
```

    Japanは2024年に存在する国です
    Japanの国名コードは392です
    Americaは2024年に存在する国です
    Americaの国名コードは840です
    

クラス変数に限り、クラス名を指定してアクセスすることもできます。


```python
print("現在は{}年です".format(Country.now_year))  # クラス名で属性呼び出し
```

    現在は2024年です
    

クラス変数の値を変更したいときは、基本的にクラス名を指定します。


```python
Country.now_year = 2124

print("現在は{}年です".format(Country.now_year))  # クラス名で属性呼び出し
```

    現在は2124年です
    

何回インスタンス化を行われたかを管理するクラス変数`count`を定義してみます。


```python
class Country:
    # クラス変数
    now_year = time.localtime().tm_year
    count = 0

    def __init__(self, name, number, code):
        self.name = name
        self.number = number
        self.code = code
        Country.count += 1  # インスタンス化時にカウントをプラスする
```


```python
japan = Country("Japan", 81, "392")
print("{}回目の呼び出し".format(Country.count))

america = Country("America", 1, "840")
print("{}回目の呼び出し".format(Country.count))
```

    1回目の呼び出し
    2回目の呼び出し
    

「作成したクラスの機能を、別のクラスでも使いたい」といったときに、  
クラスの**継承**という仕組みを用います。

他で作成したクラスのメソッドや値を受け継ぎつつ、メソッド等の編集・追加が行えるようになります。

``` python
# クラスの継承
class <クラス名> (<継承するクラス名>):
    <処理>
```

継承されるクラスを**スーパークラス**（**親クラス**、**基底クラス**）、  
継承するクラスを**サブクラス**（**子クラス**、**派生クラス**）といいます。

スーパークラスの機能を引き継ぎ、サブクラスとして拡張することができます。


```python
# スーパークラス
class Animal():
  def __init__(self, name):
    self.name = name
    print("動物です")
```


```python
# サブクラス
# Animalクラスを継承
class Dog(Animal):
    pass

# サブクラス
# Animalクラスを継承
class Cat(Animal):
    pass
```

では空クラス`Dog`クラスと`Cat`クラスを呼び出してみましょう。


```python
taro = Dog("Taro")  # コンストラクタ実行
jiro = Cat("Jiro")  # コンストラクタ実行

print(taro.name)  # 属性呼び出し
print(jiro.name)  # 属性呼び出し
```

    動物です
    動物です
    Taro
    Jiro
    

サブクラス内でもコンストラクタを定義する場合、  
サブクラスのコンストラクタを優先するため、  
スーパークラスのコンストラクタは実行されません。


```python
# スーパークラス
class Animal():
  def __init__(self, name):
    self.name = name
    print("動物です")

# サブクラス
# Animalクラスを継承
class Dog(Animal):
  def __init__(self, name):
    self.name = name
    print("犬です")

# サブクラス
# Animalクラスを継承
class Cat(Animal):
  def __init__(self, name):
    self.name = name
    print("猫です")
```


```python
taro = Dog("Taro")  # サブクラスのコンストラクタ実行
jiro = Cat("Jiro")  # サブクラスのコンストラクタ実行

print(taro.name)  # 属性呼び出し
print(jiro.name)  # 属性呼び出し
```

    犬です
    猫です
    Taro
    Jiro
    

この問題は、**super()関数**を使うことで解消できます。

``` python
# super()関数
super().親クラスのメソッド名
```



```python
# サブクラス
# Animalクラスを継承
class Dog(Animal):
  def __init__(self, name):
    super().__init__(name=name)  # super()関数
    print("犬です")

# サブクラス
# Animalクラスを継承
class Cat(Animal):
  def __init__(self, name):
    super().__init__(name=name)  # super()関数
    print("猫です")
```


```python
taro = Dog("Taro")  # 両方のコンストラクタ実行
jiro = Cat("Jiro")  # 両方のコンストラクタ実行

print(taro.name)  # 属性呼び出し
print(jiro.name)  # 属性呼び出し
```

    動物です
    犬です
    動物です
    猫です
    Taro
    Jiro
    

サブクラスでは、親クラスで定義したメソッドの後に、追加の処理を書くことができることが分かります。

スーパークラスのメソッドを、サブクラス用に書き換える/追加することができます。  
これを**オーバーライド**といいます。

同名のメソッドを定義することで実現できます。

オーバーライドのメリットは以下の通りです。  

* 変更したいメソッドを記述し直すだけで済む  （属性や他のメソッドを書き直す必要がない）  
* 複数のメソッド名を定義する必要がなくなる  

大規模な開発になったときに、オーバーライドの恩恵が大きくなってきます。  


```python
# スーパークラス
# outputメソッドを定義
class Animal():
    def __init__(self, name):
        self.name = name

    def output(self):
        print(f"名前は{self.name}です")

# サブクラス
# Animalクラスを継承
class Dog(Animal):
    def __init__(self, name):
        self.name = name

# サブクラス
# Animalクラスを継承
class Cat(Animal):
    def __init__(self, name):
        self.name = name
```


```python
taro = Dog("Taro")
jiro = Cat("Jiro")

# スーパークラスのメソッドが呼び出される
taro.output()
jiro.output()
```

    名前はTaroです
    名前はJiroです
    

この`output`メソッドをサブクラス用に書き換えてみます。


```python
# サブクラス
# Animalクラスを継承
# outputメソッドを定義
class Dog(Animal):
    def __init__(self, name):
        self.name = name

    def output(self):
        print(f"名前は{self.name}です")
        print("犬です")

# サブクラス
# Animalクラスを継承
# outputメソッドを定義
class Cat(Animal):
    def __init__(self, name):
        self.name = name

    def output(self):
        print(f"名前は{self.name}です")
        print("猫です")
```


```python
taro = Dog("Taro")
jiro = Cat("Jiro")

# サブクラスのメソッドが呼び出される
taro.output()
jiro.output()
```

    名前はTaroです
    犬です
    名前はJiroです
    猫です
    

### 3.3 ファイルの入出力

プログラムからテキストファイルの読み書きをするには、次の手順で行います。  

①ファイルを開く  
②ファイルに書き込む or 読み込む  
③ファイルを閉じる  

ファイルを開く際には、組み込み関数である **`open`関数** を使用します。

``` python
# ファイルを開く
open (<ファイル名>, <モード>)
```

第1引数として開くファイルの名前、第2引数として**モード**を指定します。  
モードは、開いたファイルをどのように操作するかを示す文字です。

ファイルに書き込む際には、ファイルオブジェクトが持つ`write`メソッドを使って、  
開いたファイルにデータを書き込んでいます。

入力された内容に改行を表すエスケープシーケンス`\n`を付けているため、
書き込むたびに改行が行われます。

ファイルを閉じる際には、ファイルオブジェクトの`close`メソッドを使用します。

必要なファイル操作が終わったら、すぐに閉じる処理が行われるようにすると安全です。


```python
# 書き込む内容を定義する
text = "Banana 200\nLemon 150\nApple 120\nGrape 300"

# 書き込みモードでファイルを開く
file = open("fruits.txt", 'w+')

# テキストをファイルに書き込む
# GoogleColabにてファイルが生成されています
file.write(text + "\n")

# ファイルを閉じる
file.close()

# ファイルからの読み込みと出力
with open("fruits.txt", mode="r") as f:
    read_text = f.read()
    print("ファイルから読み込んだ内容:")
    print(read_text)
```

    ファイルから読み込んだ内容:
    Banana 200
    Lemon 150
    Apple 120
    Grape 300
    
    

開いたファイルを確実に閉じたい場合は、**`with`文**を使います。

``` python
with ファイルを開く処理 as 変数 :
  ファイルを操作する処理
```

`with`文でファイルを開き、`with`ブロックの中で開いたファイルに関する操作を行います。  
そして、`with`ブロックが終了すると、自動的にファイルを閉じる処理が行われます。


```python
# 書き込む内容
text = "Banana 200\nLemon 150\nApple 120\nGrape 300\n"

with open("fruits.txt",mode="w+") as f:
  f.write(text + "\n")

# ファイルからの読み込みと出力
with open("fruits.txt", mode="r") as f:
    read_text = f.read()
    print("ファイルから読み込んだ内容:")
    print(read_text)
```

    ファイルから読み込んだ内容:
    Banana 200
    Lemon 150
    Apple 120
    Grape 300
    
    
    

モードの指定方法を変更することで、微妙な変化があります。


```python
import os

def delete_and_write_file():
    # ファイルの削除
    if os.path.exists("fruits.txt"):
        os.remove("fruits.txt")

    # ファイルへの書き込み
    with open("fruits.txt", mode="w+") as f:
        f.write("Banana 200\nLemon 150\nApple 120\nGrape 300\n")
```

モードとして **`r+`** を指定すると、既存のデータを読み込んだ後、  
データの先頭から書き込み・読み込みが行えるようになります。


```python
# ファイルの初期化
delete_and_write_file()

# 新しく書き込む内容
new_text = "Banana 270\nLemon 220"

# r+
# データの先頭から書き込みを行う
with open("fruits.txt", mode="r+") as f:
    f.write(new_text + "\n")

# ファイルからの読み込みと出力
with open("fruits.txt", mode="r") as f:
    read_text = f.read()
    print("ファイルから読み込んだ内容:")
    print(read_text)

```

    ファイルから読み込んだ内容:
    Banana 270
    Lemon 220
    Apple 120
    Grape 300
    
    

モードとして **`w+`** を指定すると、既存のデータを読み込んだ後、  
データの内容がすべて更新されたうえで、書き込み・読み込みが行えるようになります。


```python
# ファイルの初期化
delete_and_write_file()

# 新しく書き込む内容
new_text = "Banana 270\nLemon 220"

# w+
# データをすべて更新し書き込みを行う
with open("fruits.txt", mode="w+") as f:
    f.write(new_text + "\n")

# ファイルからの読み込みと出力
with open("fruits.txt", mode="r") as f:
    read_text = f.read()
    print("ファイルから読み込んだ内容:")
    print(read_text)
```

    ファイルから読み込んだ内容:
    Banana 270
    Lemon 220
    
    

モードとして **`a+`** を指定すると、既存のデータを読み込んだ後、  
データの末尾から書き込み・読み込みが行えるようになります。


```python
# ファイルの初期化
delete_and_write_file()

# 新しく書き込む内容
new_text = "Banana 270\nLemon 220"

# a+
# データの末尾から書き込みを行う
with open("fruits.txt", mode="a+") as f:
    f.write(new_text + "\n")

# ファイルからの読み込みと出力
with open("fruits.txt", mode="r") as f:
    read_text = f.read()
    print("ファイルから読み込んだ内容:")
    print(read_text)
```

    ファイルから読み込んだ内容:
    Banana 200
    Lemon 150
    Apple 120
    Grape 300
    Banana 270
    Lemon 220
    
    

**`readline`メソッド**を使うと、テキストファイルを一行ずつ読み込み、  
文字列として取得することができます。

テキストファイル内のデータが多いときによく用いられます。


```python
# ファイルの初期化
delete_and_write_file()

# 読み込み
with open("fruits.txt", mode="r+") as f:
  line = f.readline()
  # ファイルの中のテキストがなくなるまで読み込み
  while line:
    print(line, end="")
    line = f.readline()
```

    Banana 200
    Lemon 150
    Apple 120
    Grape 300
    


```python
# ファイルの初期化
delete_and_write_file()

# 管理する辞書
fruits_dic = dict()

# データの読み込み
with open("fruits.txt",mode="r+") as f:
  line = f.readline()
  # ファイルの中のテキストがなくなるまで読み込み
  while line:

    """
    line.split():取得した文字列を空白を区切り文字にして分ける
    line.split()[0]:果物
    line.split()[1]:値段 int型に変換している
    """
    fruits_dic[line.split()[0]] = int(line.split()[1])
    line = f.readline()

print(fruits_dic)
```

    {'Banana': 200, 'Lemon': 150, 'Apple': 120, 'Grape': 300}
    

**`readlines`メソッド**を使うと、テキストファイルを全行読み込み、  
`list`として取得することができます。


```python
# ファイルの初期化
delete_and_write_file()

with open("fruits.txt", mode="r+") as f:
  lines = f.readlines()
  print(lines)
```

    ['Banana 200\n', 'Lemon 150\n', 'Apple 120\n', 'Grape 300\n']
    

**`f.read().splitlines()`** とすると、改行`\n`の表示を消すことができます。


```python
# ファイルの初期化
delete_and_write_file()

with open("fruits.txt", mode="r+") as f:
  lines = f.read().splitlines()
  print(lines)
```

    ['Banana 200', 'Lemon 150', 'Apple 120', 'Grape 300']
    

### 3.4 例外処理

Pythonには、以下の2つのエラーが存在します。

* Syntax error（構文エラー）：書き方が正しくないケース
* Exception（例外）：書き方は合っていてもプログラムが動かないケース

構文エラーはもう正しいコードを書くしかありません。

例外のうち、前もって想定できる原因に対しては、その処理法を書くことができます。  
これを**例外処理**といいます。

例えば、何かを0で割ろうとするとExceptionが発生します。


```python
2023 / 0
```


    ---------------------------------------------------------------------------

    ZeroDivisionError                         Traceback (most recent call last)

    <ipython-input-2-44ad9b9598a6> in <module>
    ----> 1 2023 / 0
    

    ZeroDivisionError: division by zero


このように予想されるエラーについて、例外処理を書くことができます。  
詳しくは[公式ドキュメント](https://docs.python.org/ja/3/tutorial/errors.html)を参照してください。

最も基本の構文が「**try–except**」です。

``` python
# try-except文
try;
    <例外が起こりうるコード>
except <例外> as <変数>:
    <例外が起きたときに実行するコード>
```


2つの変数の割り算を行うdivide()関数を例にします。


```python
def divide(a, b):
    print(f"計算結果：{a/b}")

# 正常に実行される
divide(1, 3)

# ZeroDivisionError発生
divide(1, 0)
```

    計算結果：0.3333333333333333
    


    ---------------------------------------------------------------------------

    ZeroDivisionError                         Traceback (most recent call last)

    <ipython-input-34-48c3f98c021c> in <cell line: 5>()
          3 
          4 divide(1, 3)
    ----> 5 divide(1, 0)
    

    <ipython-input-34-48c3f98c021c> in divide(a, b)
          1 def divide(a, b):
    ----> 2   print(f"計算結果：{a/b}")
          3 
          4 divide(1, 3)
          5 divide(1, 0)
    

    ZeroDivisionError: division by zero



```python
def divide(a, b):
    # 例外処理
    # 例外が起こりうる部分
    try:
        print(f"計算結果：{a/b}")

    # 例外発生時に実行
    except ZeroDivisionError:
        print("0では割り算できません")

divide(1, 3)
divide(1, 0)
```

    計算結果：0.3333333333333333
    0では割り算できません
    

例外は引数に格納することができます。


```python
def divide(a, b):
    # 例外処理
    # 例外が起こりうる部分
    try:
        print(f"計算結果：{a/b}")

    # 例外発生時に実行
    except ZeroDivisionError as e:  # 変数名を「e」とすることが多い
        print(e)
        print("0では割り算できません")

divide(1, 3)
divide(1, 0)
```

    計算結果：0.3333333333333333
    division by zero
    0では割り算できません
    

今度は数値を文字列で割ろうとした場合について考えてみます。


```python
def divide(a, b):
    # 例外処理
    # 例外が起こりうる部分
    try:
        print(f"計算結果：{a/b}")

    # 例外発生時に実行
    except ZeroDivisionError as e:
        print(e)
        print("0では割り算できません")

divide(1, "0")  # 文字列では割り算できない
```


    ---------------------------------------------------------------------------

    TypeError                                 Traceback (most recent call last)

    <ipython-input-18-507f73b880e8> in <module>
          6     print("0では割り算できません")
          7 
    ----> 8 divide(1, "0")  # 文字列では割り算できない
    

    <ipython-input-18-507f73b880e8> in divide(a, b)
          1 def divide(a, b):
          2   try:
    ----> 3     print(f"計算結果：{a/b}")
          4   except ZeroDivisionError as e:
          5     print(e)
    

    TypeError: unsupported operand type(s) for /: 'int' and 'str'



```python
def divide(a, b):
    # 例外処理
    # 例外が起こりうる部分
    try:
        print(f"計算結果：{a/b}")

    # 例外発生時に実行
    except ZeroDivisionError as e:
        print(e)
        print("0では割り算できません")

    # 例外発生時に実行
    except TypeError as e:
        print(e)
        print("文字列の割り算はできません")

divide(1, "0")  # 文字列では割り算できない
```

    unsupported operand type(s) for /: 'int' and 'str'
    文字列の割り算はできません
    

例外が起きなかったときに実行したいコードがある場合は、  
「**try–except–else**」を使います。

``` python
# try-except-else文
try:
  <例外が起こりうるコード>
except <例外> as <変数>:
  <例外が起きたときに実行するコード>
else:
  <例外が起きなかったときに実行するコード>
```

例外が起きたら実行したくないコードをこの中に書くようにします。


```python
def divide(a, b):
    # 例外処理
    # 例外が起こりうる部分
    try:
        print(f"計算結果：{a/b}")

    # 例外発生時に実行
    except ZeroDivisionError as e:
        print(e)
        print("0では割り算できません")

    # 例外発生時に実行
    except TypeError as e:
        print(e)
        print("文字列の割り算はできません")

    # 例外非発生時に実行
    else :
        print("正常に終了しました")

divide(1, 2)
divide(1, "0")  # 例外が発生するのでelse部分は出力されない
```

    計算結果：0.5
    正常に終了しました
    unsupported operand type(s) for /: 'int' and 'str'
    文字列の割り算はできません
    

例外の発生有無にかかわらず実行したいコードがある場合は、  
「**try–except–finally**」を使います。

``` python
# try-except-finally文
try:
  <例外が起こりうるコード>
except <例外> as <変数>:
  <例外が起きたときに実行するコード>
finally:
  <必ず実行するコード>
```




```python
def divide(a, b):
    # 例外処理
    # 例外が起こりうる部分
    try:
        print(f"計算結果：{a/b}")

    # 例外発生時に実行
    except ZeroDivisionError as e:
        print(e)
        print("0では割り算できません")

    # 例外発生時に実行
    except TypeError as e:
        print(e)
        print("文字列の割り算はできません")

    # 常に実行
    finally :
        print("全ての処理が終了しました")

divide(1, "0")
divide(1, 2)
```

    unsupported operand type(s) for /: 'int' and 'str'
    文字列の割り算はできません
    全ての処理が終了しました
    計算結果：0.5
    全ての処理が終了しました
    

例外をキャッチするが、特に何もしない場合は  **`pass`** を使います。



```python
def divide(a, b):
    # 例外処理
    # 例外が起こりうる部分
    try:
        print(f"計算結果：{a/b}")

    # 例外発生時に実行
    except ZeroDivisionError as e:
        print(e)
        print("0では割り算できません")

    # 例外発生時に実行
    # 特に何もしない
    except TypeError as e:
        pass

    # 常に実行
    finally :
        print("全ての処理が終了しました")

divide(1, "0")
# divide(1, 2)
```

    全ての処理が終了しました
    

特定の例外を発生させたいときは、
**`raise`** を使います。

`try-except`をテストしたいときによく使われます。


```python
"""
    いちいち「print(f"計算結果：{a/b}")」と(a,b)を指定してテストするのは面倒
    raiseすることでテストが簡単になる
"""

try:
    # TODO あとで削除する
    raise ZeroDivisionError
except ZeroDivisionError as e:
    print("0では割り算できません")
```

    0では割り算できません
    

exceptの中でraiseを記述すると、その例外を発生させることができます。

プログラムをテストするときに使うことができます。


```python
try:
    # TODO あとで削除する
    raise ZeroDivisionError
except ZeroDivisionError as e:
    print("0では割り算できません")
    raise
```

    0では割り算できません
    


    ---------------------------------------------------------------------------

    ZeroDivisionError                         Traceback (most recent call last)

    <ipython-input-46-d4990166e039> in <cell line: 1>()
          1 try:
          2     # TODO あとで削除する
    ----> 3     raise ZeroDivisionError
          4 except ZeroDivisionError as e:
          5     print("0では割り算できません")
    

    ZeroDivisionError: 


### 3.5 JSONデータ処理

**JSON**（JavaScript Object Notation）は、データを効率的に格納、交換、解析するための軽量なデータ形式です。  
Pythonでは、JSON形式のデータを処理するための標準ライブラリが提供されています。

JSONデータは、ディクショナリやリストのようなネストされた構造を持つテキスト形式のデータです。  
オブジェクト（ディクショナリ）形式や配列（リスト）形式など、柔軟な形式が存在します。

``` json
{
    "name": "Japan",
    "number": 81,
    "code": "392",
    "code_alpha": ["JP", "JPN"]
}

```

``` json
[
  {
      "name": "Japan",
      "number": 81,
      "code": "392"
  },
  {
      "name": "America",
      "number": 1,
      "age": "840
  }
]
```

JSONデータをPythonで処理する際には、  
**`json.loads()`** 関数を使用してJSON文字列をディクショナリやリストに変換します。  

**※JSON形式ではキーと文字列はダブルクォート（"）で囲まれている必要がある**



```python
import json

# JSON文字列
json_data = '{"name": "Japan", "number": 81, "code": "392", "code_alpha": ["JP", "JPN"]}'

# JSON文字列をディクショナリに変換
data = json.loads(json_data)

# ディクショナリの内容を出力
print(type(data), data)
```

    <class 'dict'> {'name': 'Japan', 'number': 81, 'code': '392', 'code_alpha': ['JP', 'JPN']}
    


```python
import json

# JSON文字列
json_data = '[{"name": "Japan", "number": 81, "code": "392"}, {"name": "America", "number": 1, "code": "840"}]'

# JSON文字列をディクショナリに変換
data = json.loads(json_data)

# ディクショナリの内容を出力
print(type(data), data)
```

    <class 'list'> [{'name': 'Japan', 'number': 81, 'code': '392'}, {'name': 'America', 'number': 1, 'code': '840'}]
    

また、JSONデータをPythonオブジェクトからJSON文字列に変換するには、**`json.dumps()`** 関数を使用します。


```python
import json

# JSONデータ
json_data = {"name": "Japan", "number": 81, "code": "392", "code_alpha": ["JP", "JPN"]}

# ディクショナリをJSON文字列に変換
# インデント幅を指定すると要素ごとに改行・インデントされる
data = json.dumps(json_data, indent=4)

# JSON文字列を出力
print(type(data), "\n", data)
```

    <class 'str'> 
     {
        "name": "Japan",
        "number": 81,
        "code": "392",
        "code_alpha": [
            "JP",
            "JPN"
        ]
    }
    


```python
import json

# JSONデータ
json_data = [{"name": "Japan", "number": 81, "code": "392"}, {"name": "America", "number": 1, "code": "840"}]

# ディクショナリをJSON文字列に変換
# インデント幅を指定すると要素ごとに改行・インデントされる
data = json.dumps(json_data, indent=2)

# JSON文字列を出力
print(type(data), "\n", data)
```

    <class 'str'> 
     [
      {
        "name": "Japan",
        "number": 81,
        "code": "392"
      },
      {
        "name": "America",
        "number": 1,
        "code": "840"
      }
    ]
    

PythonオブジェクトをJSONファイルとして保存するには、**`json.dump()`** 関数を使用します。


```python
import json

# JSONデータ
json_data = {"name": "Japan", "number": 81, "code": "392", "code_alpha": ["JP", "JPN"]}

# ディクショナリをJSONファイルに変換
# 第一引数：Pythonオブジェクト  第二引数：ファイルオブジェクト
# インデント幅を指定すると要素ごとに改行・インデントされる
with open('test1.json', 'w') as f:
    json.dump(json_data, f, indent=4)
```


```python
import json

# JSONデータ
json_data = [{"name": "Japan", "number": 81, "code": "392"}, {"name": "America", "number": 1, "code": "840"}]

# ディクショナリをJSONファイルに変換
# 第一引数：Pythonオブジェクト  第二引数：ファイルオブジェクト
# インデント幅を指定すると要素ごとに改行・インデントされる
with open('test2.json', 'w') as f:
    json.dump(json_data, f, indent=2)
```

JSONファイルをPythonオブジェクトとして読み込むには、**`json.load()`** 関数を使用します。


```python
import json

# jsonファイル読み込み
with open('test1.json') as f:
    data = json.load(f)

# ディクショナリの内容を出力
print(type(data), data)
```

    <class 'dict'> {'name': 'Japan', 'number': 81, 'code': '392', 'code_alpha': ['JP', 'JPN']}
    


```python
import json

# jsonファイル読み込み
with open('test2.json') as f:
    data = json.load(f)

# ディクショナリの内容を出力
print(type(data), data)
```

    <class 'list'> [{'name': 'Japan', 'number': 81, 'code': '392'}, {'name': 'America', 'number': 1, 'code': '840'}]
    

JSONデータを処理することで、ウェブ上のさまざまなサービスやデータソースから情報を取得し、  
それを自分のプログラムに取り込むことができます。

その中の一つの方法が**API**です。  
APIから戻ってきたデータは **JSON形式** であることが多いとされています。



**API**（Application Programming Interface）は、アプリケーション間でデータや機能を共有するためのインターフェースです。

APIは、他のアプリケーションやウェブサービスと連携してデータを取得したり、機能を利用したりするために使用されます。

APIにはいくつかの種類があります。

- **Web API** : インターネットを通じてアクセスできるAPIで、通常はHTTPリクエストを使用してデータを取得します。
- **ライブラリ/API** : ソフトウェア内の機能を呼び出すためのライブラリやAPI。
- **ハードウェア/API** : デバイスやハードウェアとの通信を可能にするAPI。  



APIを利用するためには、通常は以下の手順が必要です。

1. **APIキーの取得（必要な場合があります）**：一部のAPIは、APIキーを提供して、アクセスを制御します。
2. **APIエンドポイントの特定**：APIエンドポイントは、APIにアクセスするためのURLです。
3. **リクエストの送信**：HTTPリクエスト（GET、POSTなど）を使用してAPIエンドポイントにリクエストを送信します。
4. **レスポンスの処理**：APIからのレスポンスを受け取り、必要な情報を処理します。

Pythonでは、主にWeb APIを使用して外部サービスとの連携を行います。  


ここでは、天気予報APIを使用して、Pythonで天気情報を取得する実践プロジェクトを行います。  
ここで用いたAPIについてはこちら → [「URL Builder」公式エディタ](https://open-meteo.com/en/docs#api_form)




```python
import json

# 天気予報APIのエンドポイントとクエリパラメータ
# ここでは北海道札幌市の座標を指定
url = 'https://api.open-meteo.com/v1/forecast'
params = {
    'latitude': 43.0667,
    'longitude': 141.35,
    'daily': 'temperature_2m_max,temperature_2m_min,rain_sum',
    'timezone': 'Asia/Tokyo'
}

# APIリクエストを送信してレスポンスを取得
response = requests.get(url, params=params)

# レスポンスから天気情報を取得
# HTTPレスポンスオブジェクトのJSONデータをPythonのデータ構造に変換
weather_data = response.json()

# ディクショナリをJSON文字列に変換
# インデント幅を指定すると要素ごとに改行・インデントされる
print(json.dumps(weather_data, indent=4))
```

    <class 'dict'>
    {
        "latitude": 43.05,
        "longitude": 141.375,
        "generationtime_ms": 0.06306171417236328,
        "utc_offset_seconds": 32400,
        "timezone": "Asia/Tokyo",
        "timezone_abbreviation": "JST",
        "elevation": 21.0,
        "daily_units": {
            "time": "iso8601",
            "temperature_2m_max": "\u00b0C",
            "temperature_2m_min": "\u00b0C",
            "rain_sum": "mm"
        },
        "daily": {
            "time": [
                "2024-02-23",
                "2024-02-24",
                "2024-02-25",
                "2024-02-26",
                "2024-02-27",
                "2024-02-28",
                "2024-02-29"
            ],
            "temperature_2m_max": [
                -4.2,
                -3.5,
                -0.5,
                0.4,
                1.5,
                -0.6,
                -0.1
            ],
            "temperature_2m_min": [
                -9.3,
                -10.1,
                -6.9,
                -7.6,
                -4.1,
                -5.3,
                -9.1
            ],
            "rain_sum": [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0
            ]
        }
    }
    


```python
import requests

# 天気予報APIのエンドポイントとクエリパラメータ
# ここでは北海道札幌市の座標を指定
url = 'https://api.open-meteo.com/v1/forecast'
params = {
    'latitude': 43.0667,
    'longitude': 141.35,
    'daily': 'temperature_2m_max,temperature_2m_min,rain_sum',
    'timezone': 'Asia/Tokyo'
}

# APIリクエストを送信してレスポンスを取得
response = requests.get(url, params=params)

# レスポンスから天気情報を取得
weather_data = response.json()

# データを取得する
dates = weather_data['daily']['time']
max_temperatures = weather_data['daily']['temperature_2m_max']
min_temperatures = weather_data['daily']['temperature_2m_min']
rain_sums = weather_data['daily']['rain_sum']

# 天気情報を表示
# 一週間の天候予測を取得する
print("天気情報:")
print("日付:", dates)
print("最高気温:", max_temperatures)
print("最低気温:", min_temperatures)
print("降雨量:", rain_sums)
```

    天気情報:
    日付: ['2024-02-23', '2024-02-24', '2024-02-25', '2024-02-26', '2024-02-27', '2024-02-28', '2024-02-29']
    最高気温: [-4.2, -3.5, -0.5, 0.4, 1.5, -0.6, -0.1]
    最低気温: [-9.3, -10.1, -6.9, -7.6, -4.1, -5.3, -9.1]
    降雨量: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    


```python
import plotly.graph_objects as go
from plotly.subplots import make_subplots

# グラフを作成する
fig = make_subplots(specs=[[{"secondary_y": True}]])

# 最高気温の折れ線グラフを追加する
fig.add_trace(go.Scatter(x=dates, y=max_temperatures, mode='lines+markers', name='Max Temperature', yaxis='y1'))

# 最低気温の折れ線グラフを追加する
fig.add_trace(go.Scatter(x=dates, y=min_temperatures, mode='lines+markers', name='Min Temperature', yaxis='y1'))

# 降水量の棒グラフを追加する
fig.add_trace(go.Bar(x=dates, y=rain_sums, name='Rain Sum', yaxis='y2'))

# グラフのレイアウトを設定する
fig.update_xaxes(title="Date", showgrid=False)
fig.update_yaxes(title="Temperature (°C)", showgrid=False, range=[min(min_temperatures)*1.25, max(max_temperatures)*1.25])
fig.update_yaxes(title="Rain Sum (mm)", showgrid=False, secondary_y=True, range=[0, max(rain_sums)*1.25])

# グラフを表示する
fig.show()
```

![](https://imgur.com/vxxv4IR.png)