5
7

Python 文法まとめ

Last updated at Posted at 2024-02-29

目次

Open In Colab

  1. プログラミング入門
  2. Python文法(基礎)
  3. Python文法(発展)

1 プログラミング入門

1.1 プログラミングとは

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

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

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

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

1.2 Pythonとは

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

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

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

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

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

WEBアプリケーション開発

(そのほかのツールはこちらなどを参照してください)

  • Flask
    必要最低限の機能だけを揃えた軽量Webアプリケーションフレームワーク。
    分かりやすい説明記事はこちら
  • Django
    フルスペックのWebアプリケーションフレームワーク。Flaskより多くの機能を提供する。
    分かりやすい説明記事はこちら
    分かりやすいFlaskとの比較記事はこちら
  • Fastapi
    高速なAPIフレームワークで、非常に高速で直感的なAPIを構築できる。
    分かりやすい入門Zenn記事はこちら
    分かりやすいFlaskとの比較記事はこちら
  • Streamlit
    データの可視化や分析を行うWebアプリを簡単に作れるフレームワーク。
    分かりやすい説明記事はこちら
    一通りの機能の紹介記事はこちら

データ分析

  • Numpy
    数値計算ライブラリで、高速な多次元配列オブジェクトやそれを操作するためのツールが提供される。
    分かりやすい入門Qiita記事はこちら
  • Pandas
    データ解析ライブラリで、データの整形や加工、解析が容易に行える。
    分かりやすい入門Qiita記事はこちら
  • matolotlib
    可視化ライブラリで、2Dグラフや3Dグラフを描画するためのツールが提供されている。
    分かりやすい入門Qiita記事はこちら
  • Seaborn
    Matplotlibをベースにした可視化ライブラリで、美しいグラフを簡単に描画できる。
    分かりやすい記事群はこちら
  • Plotly
    可視化ライブラリで、インタラクティブなグラフや図を作成するためのツールが提供されている。
    分かりやすい記事はこちら
  • SciPy
    科学技術計算のためのライブラリで、数値計算や最適化、統計など多岐に渡る機能が提供されている。
  • Polars
    高速なデータフレームライブラリで、大規模なデータセットの処理や分析に適している。
    分かりやすいPandasとの比較記事はこちら

機械学習・Ai

  • scikit-learn
    機械学習ライブラリで、様々な機械学習アルゴリズムやデータ前処理の機能が提供されている。
    分かりやすい説明記事はこちら
  • PyTorch
    機械学習ライブラリで、ニューラルネットワークの構築やトレーニングが容易に行える。
    分かりやすい説明記事はこちら
  • TensorFlow
    Googleが開発したオープンソースの機械学習ライブラリで、
    ニューラルネットワークの構築やトレーニング、デプロイメントが可能である。
    分かりやすい入門Qiita記事はこちら
  • Transformer
    自然言語処理(NLP)タスクに特化したライブラリで、BERTやGPTなどの大規模な事前学習済みモデルを提供している。
    分かりやすいZenn記事はこちら

ゲーム(GUI)アプリ開発

(ライブラリの比較記事はこちら

  • Tkinter
    GUIアプリケーションを作成するためのツールキット。
    分かりやすい記事群はこちら
  • Pygame
    2Dゲームを作成するためのライブラリで、ゲーム開発に必要な機能を提供している。

スクレイピング

(分かりやすいサイトはこちら

  • Requests
    HTTPライブラリで、HTTPリクエストを簡単に送信するためのツールが提供されている。
    分かりやすい記事はこちら
  • Beautiful Soup
    HTML/XML解析ライブラリで、Webスクレイピングやデータ抽出に使用される。
    分かりやすい記事はこちら
  • Selenium
    Webブラウザを自動化するためのツールで、Webアプリケーションのテストやスクレイピングに使用される。
    分かりやすい記事はこちら

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

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

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

特にGoolge Colaboratoryは、Google Researchが提供する無料のクラウドベースPython実行環境です。

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

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

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

1 + 2
3

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

1.4 print関数

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

print("Hello World!")
Hello world

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

print("Hello World!\nWelcome to Python!")
Hello World!
Welcome to Python!

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

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

1.5 コメント

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

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

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

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

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

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

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

1.6 エラーへの対処方法

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

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

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

1.7 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行に詰め込むことはできません。

# 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

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

全角スペースの罠

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

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

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

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

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

2 Python文法(基礎)

2.1 数値型

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

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

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

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

# 加算
7 + 3
10
# 減算
7 - 3
4
# 乗算
7 * 3
21
# 除算(商、値は実数)
7 / 3
2.3333333333333335
# 除算(商、値は整数)
7 // 3
2
# 除算(剰余)
7 % 3
1
# 冪乗
7 ** 3
343

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

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

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

(1 + 2) * 3 + 5**2
34
2 + 3 * 5
17
(2 + 3) * 5
25
2 ** 3 * 5
40
2 ** (3 * 5)
32768

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

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

2.2 文字列型

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

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

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

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

# 連結
print("Hello" + "World!")
HelloWorld!
# 反復
print("Hello" * 3)
HelloHelloHello

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

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

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

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

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

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

2.3 真偽値

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

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

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

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

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

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

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

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 がサポートされています。

# 両方の条件が満たされたらTrue
True and False
False
# どちらかの条件が満たされたらTrue
True or False
True
# 条件が満たされなかったらTrue
not True
False

2.4 変数

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

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

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)が起こってしまいます。

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']

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

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

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

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

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

# 足し算(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関数のように、右辺の式の評価値がない場合も存在します。

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

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

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

# is演算子
x = print(2 + 3)
print("x is None:", x)
5
x is None: None
x = 1
y = 1
print("x is y:", x is y)
x is y: True

2.5 オブジェクト

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

python_3-1.png

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

# 環境によって違う値になります
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を管理しています。

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

# 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

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

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

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

# 文字列オブジェクトを生成
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
# 文字列を区切る
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関数を使うと、変数にどのような型の値が格納されているかを調べることができます。

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

print(type(name))
print(type(number))
print(type(age))
<class 'str'>
<class 'str'>
<class 'int'>

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

変換先の型名(式)
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です

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

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

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のカッコ内に、埋め込みたい値をカンマ区切りで並べます。

name = "Japan"
number = 81

print("{}の番号は{}です".format(name, number))
Japanの番号は81です
# 数値を10桁の幅で表示する
# 先頭に3文字分の余白(「整数部3桁 + ドット1桁 + 小数部3桁」)

num = 123.456
print('{:10}'.format(num))
# =>    123.456
   123.456
# 小数点以下の桁数を1桁と指定

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

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

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

name = "Japan"
number = 81

print(f"{name}の番号は{number}です")
Japanの番号は81です
# 数値を10桁の幅で表示する
# 先頭に3文字分の余白(「整数部3桁 + ドット1桁 + 小数部3桁」)

num = 123.456
print(f'{num:10}')
# =>    123.456
   123.456
# 小数点以下の桁数を1桁と指定

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

2.8 入力処理

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

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

name = "Taro"

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

print(f"{name}さんの年齢は {age}歳 です ")
print(f"4年後は {int(age)+4}歳 です")  # 文字列型→整数型に変換
年齢を入力してください
20
Taroさんの年齢は 20歳 です 
4年後は 24歳 です

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

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の記述が必要です。

# ライブラリのインポート
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構文(基本形)
if <条件式>:
    <(条件式がTrueのときに実行する)処理>
else
    <(条件式が成立しなかったときの)処理>
  • ifのみの構文(条件式が成立しなかったときには何もしない場合)
if <条件式>:
    <(条件式がTrueのときに実行する)処理>
  • if-elif構文(複数の条件式が必要な場合)
if <条件式0>:
    <(条件式0がTrueのときに実行する)処理>
elif <条件式1>:
    <(条件式0がFalse条件式1がTrueのときに実行する)処理>
else:
    <(すべての条件式がFalseのときに実行する)処理>

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

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

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

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

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

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構文を用いた成績判定プログラムです。

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行で記述できます。

# if文(通常)
if <条件式>:
    <(条件式がTrueのときに実行する)処理>
else
    <(条件式が成立しなかったときの)処理>
# 三項演算子
<(True時の)処理> if <条件式> else <(False時の)処理>

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

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 ループ

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

# 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

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

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

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

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

  • for
for <変数> in <イテラブル>:
    <処理>
  • while
while <条件式>:
    <(条件式がTrueの間だけ実行する)処理>

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

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

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

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

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

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

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

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

range(start, stop, step)
  • start: 範囲の開始値(デフォルトは0)
  • stop: 範囲の終了値(この値は含まれない)
  • step: 値の増分(デフォルトは1)

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

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

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

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

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

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

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

あえて無限ループを作るときは以下のようにします。

while True:
  <(条件式がTrueの間だけ実行する)処理>
for _ in range(3):
    print("Hello")
print("終了しました")
Hello
Hello
Hello
終了しました

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

# 縦方向のループ用
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 です。

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

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

print(f"偶数の和:{sum}")
偶数の和:30

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

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

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

print(f"偶数の和:{sum}")
偶数の和:30
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番という添え字の要素はない
test = []  # 空のリスト
print("type(test) -->", type(test))
type(test) --> <class 'list'>

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

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

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

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

# リストへのアクセス
<リスト名>[要素番号]
# 要素の参照
x = [1, 2, 3]
print("x[0] -->", x[0])
x[0] --> 1

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

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

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

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

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

<リスト名>[開始位置:終了位置:増分]
  • 開始位置 : デフォルトは先頭
  • 終了位置: デフォルトは末尾(の後ろ)
  • 増分: デフォルトは1

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

# スライス(参照)
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]

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

# 文字列"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] --> パトカー

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

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
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
# 要素の追加(リストの末尾)
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]
# 要素の削除(要素番号指定)
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() --> []
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']
# リストの複製(ダメな例)
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]
# リストの結合
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']
# 文字列のリストを一つの文字列に連結
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

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

# リスト内の文字列をすべて大文字にするプログラム
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関数を使うことで、複数のリストからそれぞれ要素を順番に取得することができます。

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関数を使うことで、繰り返しの回数とともにリストから要素を順番に取得することができます。

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

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

# 内包表記の一般形
[<> for <要素> in <イテラブル>]
# appendメソッドを使用した一般形
for <要素> in <イテラブル>:
    <リスト名>.append(<>)
# 内包表記を使ったプログラム
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]
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次元リストと呼ばれます。
表の構造を持つデータ管理などに使われます。

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 タプル

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

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

test = ()  # 空のタプル
print("type(test) -->", type(test))
type(test) --> <class 'tuple'>

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

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

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

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

# タプルへのアクセス
<タプル名>[要素番号]
# 要素の参照
x = (1, 2, 3)
print("x[0] -->", x[0])
x[0] --> 1

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

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

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

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

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

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

# タプルのパック
# 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 ディクショナリ

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

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

test = {}  # 空のディクショナリ
print("type(test) -->", type(test))
type(test) --> <class 'dict'>

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

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

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

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

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

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

# ディクショナリへのアクセス
<ディクショナリ名>[キー]
# 要素の取得
x = {"a": 1, "b": 2, "c": 3}
print('x["a"] -->', x["a"])
x["a"] --> 1

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

# 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

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

# 要素の追加
<ディクショナリ名>[新しいキー] = <新しい値>
# 要素の変更
<ディクショナリ名>[変更したい要素のキー] = <変更後の値>
# 要素の追加と変更
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}

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

# 要素の削除
del <ディクショナリ名>[削除したい値のキー]
# 要素の追加と変更
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メソッドを使います。

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メソッドを使います。

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メソッドを使います。

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関数の引数に渡すことで、
ディクショナリを"キー"でソートすることができます。

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に、辞書の値を渡すことで、
ディクショナリを"値"でソートすることができます。

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}

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

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 セット

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

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

test = set()  # 空のセット
print("type(test) -->", type(test))
type(test) --> <class 'set'>

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

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

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

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

# セットの作成
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メソッドを使います。

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メソッドを使うと、オブジェクトを指定して要素を削除できます。

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}

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

# リストとタプルの定義
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'}
# セットの定義
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では、これら集合の関係性を演算で簡単に作り出すことができます。

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はイミュータブルです。

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

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

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で最初から準備されている関数のことを、組み込み関数といいます。

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

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

# 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
# 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
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ステップが必要です。

# 関数定義
def <関数名>(<引数>, ...):
    <関数内部の処理>
# 関数呼び出し
<関数名>(<引数>, ...)

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

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

# 絶対値を求めるプログラム(関数未定義)
x = -10
if (x < 0):
    y = - x
else:
    y = x
print('x -->', x)
print('y -->', y)
x --> -10
y --> 10
# 絶対値を求める関数の定義
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になります。

# 文字列を指定された回数だけ連続して表示する関数
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

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

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

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

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

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

def <関数名>(<引数>=<デフォルト引数>, ...):
    <関数内部の処理>

これをデフォルト引数と言います。
関数呼び出しの際にその引数が省略された場合、既定値が使用されます。

# 文字列を指定された回数だけ連続して表示する関数
# デフォルト引数を定義
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を使うと、任意の個数の位置引数をタプルにまとめて
その仮引数にセットします。

# 「.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 を用いることで、仮引数の数やデータ型(リストにするなど)に
気を使わなくて済むようになります。

# 「.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個の辞書にまとめることができます。
引数の名前は辞書のキー、引数の値は辞書の値になります。

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での無名関数の対応関係は以下の通りです。

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

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

# 整数かどうか判定する関数(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 --> 実数
# 整数かどうか判定する関数(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とも相性が良いです。参考記事はこちら

# 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}

# 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
# 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]
# 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 ローカル変数とグローバル変数

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

# 変数greetはローカル変数

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

hello()
# print(greet)  # 変数greetは利用できない
greet --> Hello

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

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

greet = "Hello"

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

hello()
greet --> Hello

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

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

# 変数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することでモジュールを読み込むことができます。

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

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

# モジュールが持つ変数・関数・クラスの呼び出し
<モジュール名>.<変数名/関数名/クラス名>
# 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です

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

# 別名を付けたモジュールの利用
import モジュール名 as 別名
# 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です

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

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

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

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

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

# 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 Webアクセス

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

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

import seaborn as sns

iris = sns.load_dataset("iris")
sns.pairplot(iris)
<seaborn.axisgrid.PairGrid at 0x7efddd47d310>

png

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

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

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

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

# ライブラリのインストール
pip install <ライブラリ名>
# 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
# wikipediaライブラリをインポート
import wikipedia

wikipedia.set_lang('ja')
wikipedia.search("Python")
['Python',
 'モンティ・パイソン',
 'IDLE (Python)',
 'KML',
 'Stackless Python',
 'Eric Python IDE',
 'Anaconda (Pythonディストリビューション)',
 'Blender',
 'Ruby',
 'PyQt']
r = wikipedia.page('Python').url
print(r)
https://ja.wikipedia.org/wiki/Python

3.2 クラス

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

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

以下の形式で定義できます。

# クラスの定義
class <クラス名>
    <クラスの処理>
# 空のクラス
# 後で機能や属性を追加することが想定されている
class SampleClass:
    pass

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

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

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

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

# 空クラス
class SampleClass:
    pass

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

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

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

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

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

# クラス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です

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

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メソッドを作成してみましょう。

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です

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

def __init__(self, <引数>):
    <処理>

インスタンスの作成と属性の設定を同時に行うことができます。
コンストラクタは呼び出さなくても、インスタンス化時に自動で実行されます。

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です

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

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

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です

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

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

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      # インスタンス変数
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です

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

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

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

Country.now_year = 2124

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

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

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  # インスタンス化時にカウントをプラスする
japan = Country("Japan", 81, "392")
print("{}回目の呼び出し".format(Country.count))

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

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

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

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

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

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

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

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

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

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

print(taro.name)  # 属性呼び出し
print(jiro.name)  # 属性呼び出し
動物です
動物です
Taro
Jiro

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

# スーパークラス
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("猫です")
taro = Dog("Taro")  # サブクラスのコンストラクタ実行
jiro = Cat("Jiro")  # サブクラスのコンストラクタ実行

print(taro.name)  # 属性呼び出し
print(jiro.name)  # 属性呼び出し
犬です
猫です
Taro
Jiro

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

# super()関数
super().親クラスのメソッド名
# サブクラス
# 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("猫です")
taro = Dog("Taro")  # 両方のコンストラクタ実行
jiro = Cat("Jiro")  # 両方のコンストラクタ実行

print(taro.name)  # 属性呼び出し
print(jiro.name)  # 属性呼び出し
動物です
犬です
動物です
猫です
Taro
Jiro

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

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

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

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

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

大規模な開発になったときに、オーバーライドの恩恵が大きくなってきます。

# スーパークラス
# 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
taro = Dog("Taro")
jiro = Cat("Jiro")

# スーパークラスのメソッドが呼び出される
taro.output()
jiro.output()
名前はTaroです
名前はJiroです

このoutputメソッドをサブクラス用に書き換えてみます。

# サブクラス
# 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("猫です")
taro = Dog("Taro")
jiro = Cat("Jiro")

# サブクラスのメソッドが呼び出される
taro.output()
jiro.output()
名前はTaroです
犬です
名前はJiroです
猫です

3.3 ファイルの入出力

プログラムからテキストファイルの読み書きをするには、次の手順で行います。

①ファイルを開く
②ファイルに書き込む or 読み込む
③ファイルを閉じる

ファイルを開く際には、組み込み関数である open関数 を使用します。

# ファイルを開く
open (<ファイル名>, <モード>)

第1引数として開くファイルの名前、第2引数としてモードを指定します。
モードは、開いたファイルをどのように操作するかを示す文字です。

ファイルに書き込む際には、ファイルオブジェクトが持つwriteメソッドを使って、
開いたファイルにデータを書き込んでいます。

入力された内容に改行を表すエスケープシーケンス\nを付けているため、
書き込むたびに改行が行われます。

ファイルを閉じる際には、ファイルオブジェクトのcloseメソッドを使用します。

必要なファイル操作が終わったら、すぐに閉じる処理が行われるようにすると安全です。

# 書き込む内容を定義する
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を使います。

with ファイルを開く処理 as 変数 :
  ファイルを操作する処理

with文でファイルを開き、withブロックの中で開いたファイルに関する操作を行います。
そして、withブロックが終了すると、自動的にファイルを閉じる処理が行われます。

# 書き込む内容
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

モードの指定方法を変更することで、微妙な変化があります。

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+ を指定すると、既存のデータを読み込んだ後、
データの先頭から書き込み・読み込みが行えるようになります。

# ファイルの初期化
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+ を指定すると、既存のデータを読み込んだ後、
データの内容がすべて更新されたうえで、書き込み・読み込みが行えるようになります。

# ファイルの初期化
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+ を指定すると、既存のデータを読み込んだ後、
データの末尾から書き込み・読み込みが行えるようになります。

# ファイルの初期化
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メソッドを使うと、テキストファイルを一行ずつ読み込み、
文字列として取得することができます。

テキストファイル内のデータが多いときによく用いられます。

# ファイルの初期化
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
# ファイルの初期化
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として取得することができます。

# ファイルの初期化
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の表示を消すことができます。

# ファイルの初期化
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が発生します。

2023 / 0
---------------------------------------------------------------------------

ZeroDivisionError                         Traceback (most recent call last)

<ipython-input-2-44ad9b9598a6> in <module>
----> 1 2023 / 0


ZeroDivisionError: division by zero

このように予想されるエラーについて、例外処理を書くことができます。
詳しくは公式ドキュメントを参照してください。

最も基本の構文が「try–except」です。

# try-except文
try;
    <例外が起こりうるコード>
except <例外> as <変数>:
    <例外が起きたときに実行するコード>

2つの変数の割り算を行うdivide()関数を例にします。

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
def divide(a, b):
    # 例外処理
    # 例外が起こりうる部分
    try:
        print(f"計算結果:{a/b}")

    # 例外発生時に実行
    except ZeroDivisionError:
        print("0では割り算できません")

divide(1, 3)
divide(1, 0)
計算結果:0.3333333333333333
0では割り算できません

例外は引数に格納することができます。

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では割り算できません

今度は数値を文字列で割ろうとした場合について考えてみます。

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'
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」を使います。

# try-except-else文
try:
  <例外が起こりうるコード>
except <例外> as <変数>:
  <例外が起きたときに実行するコード>
else:
  <例外が起きなかったときに実行するコード>

例外が起きたら実行したくないコードをこの中に書くようにします。

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」を使います。

# try-except-finally文
try:
  <例外が起こりうるコード>
except <例外> as <変数>:
  <例外が起きたときに実行するコード>
finally:
  <必ず実行するコード>
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 を使います。

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をテストしたいときによく使われます。

"""
    いちいち「print(f"計算結果:{a/b}")」と(a,b)を指定してテストするのは面倒
    raiseすることでテストが簡単になる
"""

try:
    # TODO あとで削除する
    raise ZeroDivisionError
except ZeroDivisionError as e:
    print("0では割り算できません")
0では割り算できません

exceptの中でraiseを記述すると、その例外を発生させることができます。

プログラムをテストするときに使うことができます。

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データは、ディクショナリやリストのようなネストされた構造を持つテキスト形式のデータです。
オブジェクト(ディクショナリ)形式や配列(リスト)形式など、柔軟な形式が存在します。

{
    "name": "Japan",
    "number": 81,
    "code": "392",
    "code_alpha": ["JP", "JPN"]
}

[
  {
      "name": "Japan",
      "number": 81,
      "code": "392"
  },
  {
      "name": "America",
      "number": 1,
      "age": "840
  }
]

JSONデータをPythonで処理する際には、
json.loads() 関数を使用してJSON文字列をディクショナリやリストに変換します。

※JSON形式ではキーと文字列はダブルクォート(")で囲まれている必要がある

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']}
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() 関数を使用します。

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"
    ]
}
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() 関数を使用します。

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)
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() 関数を使用します。

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']}
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」公式エディタ

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
        ]
    }
}
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]
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()

5
7
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
7