【自前python講座】基本的な演算/真偽値/None/文字列/リスト/タプル/集合/辞書について

python-operator-types プログラミング
python-operator-types



自前の python 講座用資料です.
今回は,対話式プログラミング環境の jupyterlab,もしくは,インタラクティブシェルを用いて,基本的な演算や真偽値,None,文字列,リスト,タプル,集合,辞書の扱いについて紹介いたします.
注意:すべてについては説明せず,よく使われる処理を優先的に記載いたします.

この記事は,主に以下の公式ドキュメントを参考にしています.

3. 形式ばらない Python の紹介 — Python 3.7.17 ドキュメント

以下のコードは,こちらの github にも保存していますので,ご参考ください.

https://github.com/KazutoMakino/PythonCourse/blob/main/002_fundamental_operation/002_fundamental_operation.ipynb

基本的な演算/真偽値/Noneについて

四則演算:

2 + 3
# 5

2 - 3
# -1

2 * 3
# 6

2 / 3
# 0.6666666666666666

3 / (2 - 1)
# 3.0

べき乗:

2**3
# 8

除法における商と余り:

5 // 2
# 2

5 % 2
# 1

代入演算:

base = 10
height = 5
base, height
# (10, 5)

triangle_area = base * height / 2
triangle_area
# 25.0

定義や値が代入されていない変数を使おうとすると,エラーを返します.

trapezoidal_area
# ---------------------------------------------------------------------------
# NameError                                 Traceback (most recent call last)
# ~\AppData\Local\Temp/ipykernel_4472/1289577273.py in <module>
# ----> 1 trapezoidal_area
#
# NameError: name 'trapezoidal_area' is not defined

変数名の頭文字はアルファベットにしてください.アンダーバー _ を使うこともできますが,コード規約により使いどころが異なります.

2_pi_r
#  File "C:\Users\anonymous\AppData\Local\Temp/ipykernel_4472/3060862857.py", line 1
#    2_pi_r
#     ^
# SyntaxError: invalid decimal literal

ブール演算,及び,比較における演算子は,次の表にまとめられ,条件式などで良く用いられます.

演算結果
x or yx が偽なら y, そうでなければ x
x and yx が偽なら x, そうでなければ y
not xx が偽なら True, そうでなければ False
<より小さい
<=以下
>より大きい
>=以上
==等しい
!=等しくない
is同一のオブジェクトである
is not同一のオブジェクトでない
and, or, not

引用元:https://docs.python.org/ja/3.7/library/stdtypes.html

1 < 3
# True

1 > 3
# False

1 == 3
# False

1 != 3
# True

"a" is "b"
# <>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
# <>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
# C:\Users\anonymous\AppData\Local\Temp/ipykernel_4472/2297060732.py:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
#   "a" is "b"
# False

"a" is not "b"
# <>:1: SyntaxWarning: "is not" with a literal. Did you mean "!="?
# <>:1: SyntaxWarning: "is not" with a literal. Did you mean "!="?
# C:\Users\anonymous\AppData\Local\Temp/ipykernel_4472/1898745988.py:1: SyntaxWarning: "is not" with a literal. Did you mean "!="?
#   "a" is not "b"
# True

ここで出力された True, False は bool 型であり,整数型のサブクラス(子供みたいな関係)なので,それぞれ True は 1,False は 0 を表すので足し算が可能です.

(True + False) / (True + True) 
# 0.5

==is の違いについて,== は値が同じかを判定するのに対し,is は生成されたオブジェクトの識別値 id が同じかどうかを見るため,以下のように,True == 1True ですが,True is 1False が返ってきます.

True == 1, True is 1, False == 0, False is 0
# <>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
# <>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
# <>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
# <>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
# C:\Users\anonymous\AppData\Local\Temp/ipykernel_4472/883044353.py:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
#   True == 1, True is 1, False == 0, False is 0
# C:\Users\anonymous\AppData\Local\Temp/ipykernel_4472/883044353.py:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
#   True == 1, True is 1, False == 0, False is 0
# (True, False, True, False)

他には,何もないを表す None というものもあり,False と異なり 0 ではありません.実際,None のみを実行してみると返り値が無いので,インタラクティブシェルでは出力がありません.

None

None is False
# False

None == 0
# False

None is None
# True

None == None
#True

文字列

文字列を囲うのは,ダブルクォーテーションとシングルクォーテーションのどちらでも構いません.

"hello"
# 'hello'

'world'
# 'world'

pythonでは文字列どうしであれば普通に足し算でくっつけることができます.

hello = "hello"
hello + " " + "world"
# 'hello world'

実は,上記操作は加法の記号は不要です.しかし,+ を付けた方が見やすいですね.

"hello" " " "world"
# 'hello world'

減法,除法による文字列の操作はできません

hello - "h"
# ---------------------------------------------------------------------------
# TypeError                                 Traceback (most recent call last)
# ~\AppData\Local\Temp/ipykernel_4472/3308442367.py in <module>
# ----> 1 hello - "h"
#
# TypeError: unsupported operand type(s) for -: 'str' and 'str'

文字列の繰り返しは掛け算の記号にて可能です.

hello * 5
# 'hellohellohellohellohello'

文字列は配列のような扱いができます.pythonの配列は C 言語と同じく 0 から始まり,配列番号は [ ] の中に整数値で指定します.例えば,”hello” の 2 文字目の “e” を抜き出そうとすると,

hello[1]
# 'e'

となります.分かりにくいので “abcde” という配列を生成し,それぞれの文字を抜き出すと,

a_e = "abcde"
a_e[0], a_e[1], a_e[2], a_e[3], a_e[4]
# ('a', 'b', 'c', 'd', 'e')

a_e に 6 文字目は無いので,5 (= 6 – 1) を配列番号に指定すると,以下の通りエラーになります.

a_e[5]
# ---------------------------------------------------------------------------
# IndexError                                Traceback (most recent call last)
# ~\AppData\Local\Temp/ipykernel_4472/1358315151.py in <module>
# ----> 1 a_e[5]
#
# IndexError: string index out of range

上記において配列番号は正の整数を記入していましたが,負の整数を記載した場合は,後ろから数えて何番目かを示します.

a_e[-1], a_e[-2], a_e[-3], a_e[-4], a_e[-5]
# ('e', 'd', 'c', 'b', 'a')

1 つの要素でなく範囲指定した 2 つ以上の要素を指定したい場合は,”スライス” と呼ばれる操作を行います.スライスは 変数[i:j] というふうに記載し,この場合,\(i \le k < j\) の要素番号 k における値を取得します.

a_e[1:3], a_e[3:-1], a_e[1:], a_e[:-3], a_e[1-1 : 4-1]
# ('bc', 'd', 'bcde', 'ab', 'abc')

以下の通り,pythonにおいて要素番号を用いた文字列の変更はできません.

a_e[-1] = "zzz"
a_e
# ---------------------------------------------------------------------------
# TypeError                                 Traceback (most recent call last)
# ~\AppData\Local\Temp/ipykernel_4472/3479971852.py in <module>
# ----> 1 a_e[-1] = "zzz"
#       2 a_e
#
# TypeError: 'str' object does not support item assignment

変数を代入した文字列を生成したい場合は,f-string と呼ばれる仕組みを用いることができます(他にも.format()% を用いた方法もありますが,f-string がオススメです).f"任意の文字列 {変数名}" というふうに,文字列を表すクォーテーションの前に f を記載します.

f"a to e = {a_e}, 10 / 2 = {10 / 2}, 1/3={1/3}"
# 'a to e = abcde, 10 / 2 = 5.0, 1/3=0.3333333333333333'

文字列は,三連引用符:""" 文章 """ のようにすることで,複数行に渡って書くことが可能です.

"""
a
b
c
d
e
"""
# '\na\nb\nc\nd\ne\n'

ここで \n は改行を表し,環境における改行コード設定によって変わります.改行コードは wikipedia を参照すると,

改行コード(広義)は以下の2種類であり、システム(ソフトウェア)により片方または両方が使用される。
キャリッジリターン(英: carriage return、CR、復帰)
ラインフィード(英: line feed、LF、狭義の改行)またはニューライン(newline、line break または end-of-line、EOL)
これらの用語はタイプライターが由来である。タイプライターでは印字装置は固定され、紙の方が上下左右に移動することで、文字送りや行送りが行われる。英語などの左横書きにおける「キャリッジリターン」とは、紙を固定して移動する装置(キャリッジ)を元の位置に戻す(リターン、つまり紙の左端に印字装置が来る)ことである。「ラインフィード」とは紙を必要な行(ライン)だけ上に送る(フィード、つまり下の行に印字装置が来る)ことである。
コンピュータでは、同じ文字コードを使用していても、改行コードは異なる場合があるため、異なるシステム間でのデータの際には、改行が正確に反映されない場合がある。

多くのシステムでは、改行コードを1つまたは連続する2つの特殊文字で表している。
ASCII文字コードに基づくシステムでは、CR(復帰、0x0D)、LF(改行、0x0A)、またはCR+LFで表している。
LF: UNIXやUnix系のシステム。Linux、AIX、Xenix、macOS、BeOS、Amiga、RISC OSなど。
CR+LF: CP/M、MP/M、MS-DOS、OS/2、Microsoft Windows。
CR: コモドールによるシステム、Apple IIファミリ、Mac OS(バージョン9まで)、OS-9。
Unicodeでは、CR(U+000D)とLF(U+000A)に加えて、「次の行」(next line)を示すNEL(U+0085)、行区切り文字(line separator)を示すLS(U+2028)、段落区切り文字(paragraph separator)を示すPS(U+2029)が提供される。
EBCDICシステム
IBMのメインフレームシステムでは主にNEL(Next Line、0x15)を改行コードとして使う。EBCDICはCRとLFと呼ばれる制御文字も持つが、これらはASCIIにおけるCRとLFとは値が異なる。また、NELに対して異なる値を割り当てたEBCDICの亜種も存在する。なお固定長のデータセットでは、通常は改行コード自体が不要なため使用されない。
OpenVMSはレコードベースのファイルシステムを使用しており、テキストファイルの各行を1レコードとして保存する。保存する際は改行コードは記録されないが、アプリケーションから読み込まれる際に自動的に行終端記号を付加する機能がある。
インターネット上で用いられる、テキストによって情報をやりとりする通信プロトコルの多く(HTTP、SMTP、FTP、IRCなど)はプロトコルレベルでCR+LFコードを用いるよう要求しているが、アプリケーションはLFコードにも対応することが推奨されている。これは初期のインターネットサーバの多くがDEC機によって構成されていた名残である。

引用元:https://ja.wikipedia.org/wiki/%E6%94%B9%E8%A1%8C%E3%82%B3%E3%83%BC%E3%83%89

とのこと.三連引用符内で改行された文字列について,文末に \ を追加することで,その部分の出力を改行なしにすることもできます(があまり使いません).

"""\
a\
b\
c\
d\
e\
"""
# 'abcde'

\n はもちろん,クォーテーションが三連でない場合も用いることができ,改行として認識されます.

"a \n b"
# 'a \n b'

print("a \n b")
# a 
#  b

C言語と同様に,pythonにおいてもバックスラッシュ \ はエスケープシーケンス(改行やタブなど通常の文字列では表すことができない特殊な文字や機能を,規定された特別な文字の並びにより表したもの)に用いられます.pythonにおけるエスケープシーケンスは,公式ドキュメント(https://docs.python.org/ja/3.10/reference/lexical_analysis.html)を参照すると,

エスケープシーケンス意味
\newlineバックスラッシュと改行文字が無視されます
\\バックスラッシュ (\)
\'一重引用符 (')
\"二重引用符 (")
\aASCII 端末ベル (BEL)
\bASCII バックスペース (BS)
\fASCII フォームフィード (FF)
\nASCII 行送り (LF)
\rASCII 復帰 (CR)
\tASCII 水平タブ (TAB)
\vASCII 垂直タブ (VT)
\ooo8 進数値 ooo を持つ文字
\xhh16 進数値 hh を持つ文字
\N{name}Unicode データベース中で name という名前の文字
\uxxxx16-bit の十六進値 xxxx を持つ文字
\Uxxxxxxxx32-bit の十六進値 xxxxxxxx を持つ文字
escape sequence

windows におけるディレクトリパスはバックスラッシュ \(円マーク)が用いられますが,上記の関係上,エクスプローラからディレクトリパスをコピペして使おうとするとエラーになることがあります.

print("C:\Program Files (x86)\NVIDIA Corporation")
#   File "C:\Users\anonymous\AppData\Local\Temp/ipykernel_4472/1980184030.py", line 1
#     print("C:\Program Files (x86)\NVIDIA Corporation")
#           ^
# SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 22-23: malformed \N character escape

この場合はエスケープシーケンスとしてバックスラッシュの前にもう一つバックスラッシュを追加することで回避できます.

print("C:\\Program Files (x86)\\NVIDIA Corporation")
# C:\Program Files (x86)\NVIDIA Corporation

もしくは,クォーテーションの前に r もしくは R を追加し,raw 文字列とすることでエスケープシーケンスが無視されます(こちらの方が一般的).

print(r"C:\Program Files (x86)\NVIDIA Corporation")
# C:\Program Files (x86)\NVIDIA Corporation

なお,pythonにおいてパスと認識されるためには,2重バックスラッシュや raw 文字列の代わりに,バックスラッシュからスラッシュに書き換えてもOKです.

文字列の操作は他にも色々あり,文字列の後に .メソッド(...) という風に用います.
ここで,メソッドというのは,クラスオブジェクトの後ろにドット . を付けて呼び出すことで作用するサブルーチンで一種の関数です.
更に,関数というのは,関数(...) で作用させることのできるサブルーチンです.例えば,print() はモニタに出力する関数と言えます.
全ての文字列に適用できるメソッドの説明を行うことはせず,良く使われるメソッドのみ抜粋して記載いたします.

  • str.casefold(): 文字列の casefold されたコピーを返し,casefold された文字列は,大文字小文字に関係ない比較判定に使えます.
"Python" == "pytHON", "Python".casefold() == "pytHON".casefold()
# (False, True)
  • str.count(sub, start, end): start, end の範囲に部分文字列 sub が重複せず出現する回数を返します.start 及び end はオプションで,無記入の場合は start = 0, end = -1 となります.
"aaa bbb cc d".count("a"), "aaa bbb cc d".count("aa"), "aaa bbb cc d".count("a", 1, 3)
  • str.endswith(suffix, start, end): 文字列が指定された suffix で終わるなら True を,そうでなければ False を返します.start 及び end はオプションで,無記入の場合は start = 0, end = -1 となります.
"python".endswith("thon")
True
  • str.find(sub, start, end): 文字列のスライス s[start, end] に部分文字列 sub が含まれる場合,その最小のインデックスを返します.start 及び end はオプションで,無記入の場合は start = 0, end = -1 となります.見つからなかった場合は -1 を返します.
"pythonpython".find("tho"), "pythonpython".find("zzzz")
# (2, -1)
  • str.join(iterable): iterble 中の文字列を結合した文字列を返します.ここで iterable (イテラブル)は名前の通り,繰り返し可能なオブジェクトもしくはクラスの総称で,for 文で繰り返しが可能であったり,next関数で要素を順番に取り出すことが可能です.
"-".join(["a", "b", "c"])
# 'a-b-c'

["a", "b", "c"] は “a”, “b”, “c” の3つの要素が入ったリストを表し,リストも iterable オブジェクトです.リストについては,文字列メソッドの説明の後に記載します.

  • str.lower(): 小文字化された文字列を返します.
"PYthoN".lower(), "python".lower()
# ('python', 'python')
  • str.replace(old, new, count): 文字列をコピーし,現れる部分文字列 old すべてを new に置換して返します.オプション引数 count が与えられている場合,先頭から count 個の old だけを置換します.
"aaa aaaabbb caacaca dadaaaad".replace("a", "").replace(" ", "")
# 'bbbcccddd'

"Pen, pinapple, apple, pen".replace("pen", "?")
# 'Pen, pinapple, apple, ?'

"Pen, pinapple, apple, pen".casefold().replace("pen".casefold(), "?")
# '?, pinapple, apple, ?'
  • str.split(sep=None, maxsplit=-1): 文字列 sep をデリミタ文字列(区切り文字列)として区切った単語のリストを返します.maxsplit が与えられていれば,最大で maxsplit 回分割されます.maxsplit が与えられていないか -1 であれば,分割の回数に制限はなく,可能なだけ分割されたリストが返されます.
"1,2,3".split(",")
# ['1', '2', '3']

"1,2,3".split(",", maxsplit=1)
# ['1', '2,3']

"1,2,,,,,,3".split(",")
# ['1', '2', '', '', '', '', '', '3']

sep が指定されていないか None の場合,異なる分割アルゴリズムが適用され,一つのあるいは連続する空白文字が一つのデリミタと見なされます.

"1 2 3".split()
# ['1', '2', '3']

"   1    2    3 ".split()
# ['1', '2', '3']

"   1-    2  -   -  3- ".split()
# ['1-', '2', '-', '-', '3-']
  • str.startswith(prefix, start, end): 文字列が指定された prefix で始まるなら True を,そうでなければ False を返します.start 及び end はオプションで,無記入の場合は start = 0, end = -1 となります.
"python".startswith("thon"), "python".startswith("pyt")
# (False, True)
  • str.upper(): 大文字化された文字列を返します.
"pythOn".upper()
# 'PYTHON'
  • str.zfill(witdh): 長さが width になるように ASCII "0" で左図目下文字列のコピーを返します(zfill: zero fill, ゼロ埋め).先頭が符合接頭辞 + もしくは - だった場合,"0" は符号の前ではなく後に挿入されます.
"123".zfill(5), "+あ".zfill(5), 
# ('00123', '+000あ')

リスト

pythonにおいて配列は,標準関数に限ると list もしくは array によって表現できます.
list は単なる入れ物として汎用的に用いることができ,要素間における型の違いは問われません.
一方 array は標準関数のインポートが必要であり,かつ,要素の型は配列定義時に決定されるので同じである必要があります.
前者の list を用いることがほとんどであるので,こちらの説明を行います.

リスト list[a, b, c, ...][] 内に , 区切りで要素を並べただけのもので,文字列でも用いたインデックス(要素番号参照)とスライスを用いることができます.

a = [0, 1, 2, "a", "b", "c"]
a
# [0, 1, 2, 'a', 'b', 'c']

a[0], a[-1], a[1:4]
# (0, 'c', [1, 2, 'a'])

また,文字列同様,加法と乗法による文字列操作も可能です.

a + a
# [0, 1, 2, 'a', 'b', 'c', 0, 1, 2, 'a', 'b', 'c']

a * 3
# [0, 1, 2, 'a', 'b', 'c', 0, 1, 2, 'a', 'b', 'c', 0, 1, 2, 'a', 'b', 'c']

文字列とは異なり,リストは可変な型なので要素を入れ替えたりすることができます.

b = [0, 1, 2]
b[0] = "a"
b[1] = b[2]
b[2] = b[2]**4
b
# ['a', 2, 16]

スライスごと代入することも可能です.

c = [0, 1, 2, 3, 4]
c[1:4] = ["a", "b", "c"]
c
# [0, 'a', 'b', 'c', 4]

入れ子構造もリストから作成することが可能です.

d0 = [0, 1, 2]
d1 = ["a", "b", "c", "d"]
d = [d0, d1]
d
# [[0, 1, 2], ['a', 'b', 'c', 'd']]

要素やリスト全体の削除には del を用います.

e = ["test", "delete"]
del e[-1]
e
# ['test']

del e
e
# ---------------------------------------------------------------------------
# NameError                                 Traceback (most recent call last)
# ~\AppData\Local\Temp/ipykernel_4472/2743830455.py in <module>
#       1 del e
# ----> 2 e
#
# NameError: name 'e' is not defined

変数 e が削除された後,再び e を出力しようとしたので,未定義であるとエラーがでました.

空のリストの作成は,要素を何も書かずに [] とするだけです.

a = []
a
# []

リストの要素は,それぞれの変数に代入することができ,以下のような操作をアンパックと呼びます.

z = [1, 2, 3]
a, b, c = z
b
# 2

z = [1,2, [3,4,5,[6]]]
a, b, c = z
c0, c1, c2, c3 = c
c2
# 5

z = [1, 2, 3]
a, b = z
b
# ---------------------------------------------------------------------------
# ValueError                                Traceback (most recent call last)
# ~\AppData\Local\Temp/ipykernel_4472/1657746003.py in <module>
#       1 z = [1, 2, 3]
# ----> 2 a, b = z
#      3 b
#
# ValueError: too many values to unpack (expected 2)

上記のように,アンパックする際に,代入される変数の数が要素の数よりも少ない場合は ValueError が送出されます.
これの解決方法として,変数名にアスタリスク * を付与することにより,残りの要素がまとめて代入されます.
複数の変数にアスタリスクを付けた場合は,SyntaxError が送出されます.

z = [1, 2, 3, 4, 5]
a, *b = z
b
# [2, 3, 4, 5]

z = [1, 2, 3, 4, 5]
*a, b = z
b
# 5

z = [1, 2, 3, 4, 5]
*a, *b = z
b
#   File "C:\Users\anonymous\AppData\Local\Temp/ipykernel_4472/1964158954.py", line 2
#     *a, *b = z
#     ^
# SyntaxError: two starred expressions in assignment

リストの操作は他にも色々あり,リストの後に .メソッド(...) という風に用います.
以下,公式ドキュメント (https://docs.python.org/ja/3.7/tutorial/datastructures.html) を参考にして記載します.

list.append(x): リストの末尾に要素 x を1つ追加します.

arr = ["aaa"]
arr.append(1)
arr.append(10)
arr
# ['aaa', 1, 10]

list.extend(iterable): イテラブルの全ての要素を対象のリストに追加し,リストを拡張します.

arr = ["aaa"]
arr.extend("b")
arr.extend("ccccccc")
arr.extend(["ddd"])
arr.extend([1000])
arr
# ['aaa', 'b', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'ddd', 1000]

例えば,数字はイテラブルではないので,そのまま extend はできず,エラーになります.

arr.extend(1000)
# ---------------------------------------------------------------------------
# TypeError                                 Traceback (most recent call last)
# ~\AppData\Local\Temp/ipykernel_4472/1159857722.py in <module>
# ----> 1 arr.extend(1000)
#
# TypeError: 'int' object is not iterable

list.insert(i, x): 指定した位置に要素を挿入します.第1引数はリストのインデックスで,このインデックスを持つ要素の直前に挿入が行われます.

arr = ["a", "bb", "ccc", "dddd"]
arr.insert(1, "あ")
arr.insert(-1, 2**8)
arr
# ['a', 'あ', 'bb', 'ccc', 256, 'dddd']

list.remove(x): リスト中で x と等しい値を持つ最初の要素を削除します.該当する要素が無ければ ValueError が送出されます.

arr = ["a", "bb", "ccc", "dddd"]
arr.remove("a")
arr
# ['bb', 'ccc', 'dddd']

arr = ["a", "bb", "ccc", "dddd"]
arr.remove("b")
arr
# ---------------------------------------------------------------------------
# ValueError                                Traceback (most recent call last)
# ~\AppData\Local\Temp/ipykernel_4472/3654038372.py in <module>
#       1 arr = ["a", "bb", "ccc", "dddd"]
# ----> 2 arr.remove("b")
#       3 arr
# 
# ValueError: list.remove(x): x not in list

list.pop(i): リスト中の指定された位置にある要素をリストから削除して,その要素を返します.インデックスが指定されなければ,a.pop() はリストの末尾の要素を削除して返し,この場合も要素は削除されます.

arr = ["a", "bb", "ccc", "dddd"]
arr.pop(-1)
arr.pop(0)
arr.pop(0)
arr
# ['ccc']

list.clear(): リスト中の全ての要素を削除します.

arr = ["a", "bb", "ccc", "dddd"]
arr.clear()
arr
# []

list.index(x, start, end): リスト中で x と等しい値を持つ最初の要素の位置をゼロから始まるインデックスで返します.該当する要素が無ければ ValueError が送出されます.

arr = ["a", "bb", "ccc", "dddd"]
arr.index("bb")
# 1

arr.index("b")
# ---------------------------------------------------------------------------
# ValueError                                Traceback (most recent call last)
# ~\AppData\Local\Temp/ipykernel_4472/1344072699.py in <module>
# ----> 1 arr.index("b")
# 
# ValueError: 'b' is not in list

list.count(x): リストでの x の出現回数を返します.

arr = [1, 1, 2, 3, 4, 5, 5, 1, 1, "a"]
arr.count(1)
# 4

list.sort(key=None, reverse=False): リストの項目を,インプレース演算 (in place,元のデータを演算結果で置き換えるやりかた) でソートします.

arr = [1, 1, 2, 3, 4, 5, 5, 1, 1.00001, 1-1/10000000]
arr.sort()
arr
# [0.9999999, 1, 1, 1, 1.00001, 2, 3, 4, 5, 5]

arr = ["\n", "か", "z", "a", "aaaa", "___", "あ"]
arr.sort()
arr
# ['\n', '___', 'a', 'aaaa', 'z', 'あ', 'か']

数値と文字列が同一のリストにある場合で sort() を適用した場合はエラー TypeError が送出されます.

arr = [1, "1", 2, 3, 4, 5, 5, 1, 1.00001, 1-1/10000000]
arr.sort()
arr
# ---------------------------------------------------------------------------
# TypeError                                 Traceback (most recent call last)
# ~\AppData\Local\Temp/ipykernel_4472/2493599537.py in <module>
#       1 arr = [1, "1", 2, 3, 4, 5, 5, 1, 1.00001, 1-1/10000000]
# ----> 2 arr.sort()
#       3 arr
# 
# TypeError: '<' not supported between instances of 'str' and 'int'

list.reverse(): リストの要素をインプレース演算で逆順にします.

arr = [0, 1, 2, 5, "a", 1000]
arr.reverse()
arr
# [1000, 'a', 5, 2, 1, 0]

タプル

タプルもリストに似て,入れ物のように使います.
以下のように,タプルはカンマ区切りの値から生成できます.

1, 2, "a"
# (1, 2, 'a')

出力には ( ) がついていますが,代入(定義)の際は必ずしも ( ) は必要ではありません.

(1, 2, "a")
# (1, 2, 'a')

arr = 1,2,"a"
arr
# (1, 2, 'a')

要素が1つの場合,要素の後にカンマを入れないと,タプルでなく,単なる値として認識されます.

arr = (1)
arr
# 1

arr = (1,)
arr
# (1,)

リストは可変(ミュータブル, mutable)であることに対し,タプルは不変(イミュータブル,immutable)であるため,似ているオブジェクトに見えますが,リストで用いたメソッドの大半は使うことができず,役割が異なります.
タプルは主に,

  • 格納している要素を変更したくない場合
  • 例えば,後述する辞書型のキーはハッシュ可能な(hashable, 生存期間中変わらないハッシュ値を持ち他のオブジェクトと比較ができる)オブジェクトである必要があり,ミュータブルなタプルは自身を除いた比較結果は非等価であることから受け付けるが,イミュータブル(unhashable)なリストは受け付けられない

上記2つの場合に用いられます.引数としてミュータブルなオブジェクトのみ受け付けるライブラリも多いので,タプルとリストの出番は大きく異なると言えます.

タプルに用いることができるメソッドは,

  • index
  • count

の二つで,使い方はリストと同じなので省略します.アンパックも同様です.

空のタプルの作成は,要素を何も書かずに () とするだけです.

a = ()
a
# ()

集合

集合(set)とは,重複する要素を持たず,順序づけられていない要素の集まりで,集合演算が可能です.
集合は {a, b, ...} のように定義するか,文字列,リスト,タプルなど iterable なオブジェクトに対し,set(iterable) という風にset関数を用いることで定義できます.

{1, 2, "a", 3, 1, 2, 3, 1, 2, 3, 4, 5, 6, 7}
# {1, 2, 3, 4, 5, 6, 7, 'a'}

txt = "irohanihohetochirinuruo"
set(txt)
# {'a', 'c', 'e', 'h', 'i', 'n', 'o', 'r', 't', 'u'}

arr = [1, 5, 4, 3, 5, 5, (1,3)]
set(arr)
# {(1, 3), 1, 3, 4, 5}

arr = [1, 5, 4, 3, 5, 5, [1,3]]
set(arr)
# ---------------------------------------------------------------------------
# TypeError                                 Traceback (most recent call last)
# ~\AppData\Local\Temp/ipykernel_4472/3718866804.py in <module>
#       1 arr = [1, 5, 4, 3, 5, 5, [1,3]]
# ----> 2 set(arr)
# 
# TypeError: unhashable type: 'list'

上記の通り,set() にて集約される要素自体は immutable である必要があります.
TypeError が送出されたのは,[1, 3] が mutable であることが起因しています.

例えば二つの集合 A, B が与えられたとき,以下のような集合演算

  • 和(union): \(A \cup B\)
  • 積(intersection): \(A \cap B\)
  • 差(difference): \(A – A \cap B, B – (A \cap B)\)
  • 対称差(symmetric difference): \((A \cup B) – (A \cap B)\)

を扱うこともできます.

a = {0, 1, 2, 3, 4,    "a"}
b = {0, 2,       4, 5}
a, b
# ({0, 1, 2, 3, 4, 'a'}, {0, 2, 4, 5})

# union
a | b
# {0, 1, 2, 3, 4, 5, 'a'}

# intersection
a & b
# {0, 2, 4}

# difference
a - b, b - a
# ({1, 3, 'a'}, {5})

# symmetric difference
a ^ b
# {1, 3, 5, 'a'}

辞書

python の辞書型(dictionay)は,他の言語では連想配列(associative array)と呼ばれることもあり,要素との紐づけが配列番号ではなく,キー(key)によって紐づけられます.
キーは変更不可能な型のみ受け付けるため,リストなどのミュータブルなオブジェクトは用いることができません.
辞書は {key0: value0, key1: value1, ...} という風に,{ } の中に keyvalue の間に : を挟み,ペアで定義します.

a = {"a": 0, "b": 1, "c": 2}
a
# {'a': 0, 'b': 1, 'c': 2}

その名の通り辞書の要素を参照したいときは,配列番号でなくキーを入力することによって,関連付けられている要素を参照することができます.
参照の仕方は,dict[key] もしくは dict.get(key) です.

a["a"], a.get("c")
# (0, 2)

a = {"a": 0, "b": 1, "c": {"c0": 0, "c1": 0}}
a["c"], a["c"]["c1"]
# ({'c0': 0, 'c1': 0}, 0)

配列番号はキーではないので,リストと同じように配列番号で参照を行おうとするとエラー KeyError が送出されます.指定したキーが無い場合も同様です.

a = {"a": 0, "b": 1, "c": 2}
a[0]
# ---------------------------------------------------------------------------
# KeyError                                  Traceback (most recent call last)
# ~\AppData\Local\Temp/ipykernel_4472/1728541355.py in <module>
#       1 a = {"a": 0, "b": 1, "c": 2}
# ----> 2 a[0]
# 
# KeyError: 0
a = {"aaaa": 0, "b": 1, "c": 2, "aaaa": 3, "aaaa": {"memo": "overwritten"}}
a
# {'aaaa': {'memo': 'overwritten'}, 'b': 1, 'c': 2}

辞書の上書きと追加は,dict[key] = value として簡単に操作できます.
keydict に存在する場合は上書き,存在しない場合は新たなキーと値のペアが追加されます.

z = {"z": 0}
z["zz"] = 1
z["zzz"] = 2
z["z"] = -100
z
# {'z': -100, 'zz': 1, 'zzz': 2}

辞書型においても多くのメソッドがあります.

dict.keys(): dict からキーを返します.

a = {"a": 0, "b": 1, "c": 2}
keys = a.keys()
keys
# dict_keys(['a', 'b', 'c'])

keys[0]
# ---------------------------------------------------------------------------
# TypeError                                 Traceback (most recent call last)
# ~\AppData\Local\Temp/ipykernel_4472/4009037613.py in <module>
# ----> 1 keys[0]
# 
# TypeError: 'dict_keys' object is not subscriptable

返り値は dict_keys 型となっており,これはリストや辞書とは異なるビューオブジェクトと呼ばれるもので,.keys の対象から作成やコピーされたものではなく,単なるビュー(参照されているだけ)であるため,直接変更したり操作することはできません.
リストのように扱いたい場合は,list 関数(後述)を用いることによってリスト化できます.

keys_list = list(keys)
keys_list
# ['a', 'b', 'c']

keys_list[0]
# 'a'

dict.values(): dict から値を返します..keys() と同様にリスト化する際には list 関数を用います.

a = {"a": 0, "b": 1, "c": 2}
a.values()
# dict_values([0, 1, 2])

list(a.values())
# [0, 1, 2]

dict.items(): dict からキーと値のペアを返します..keys() と同様にリスト化する際には list 関数を用います.この際,各要素はタプルです.

a = {"a": 0, "b": 1, "c": 2}
a.items()
# dict_items([('a', 0), ('b', 1), ('c', 2)])

list(a.items())[-1]
# ('c', 2)

dict.setdefault(key, value): dict にキーと値のペアを追加します.dictkey が既存の場合は,上書きされません.

z = {"z": 0}
z.setdefault("zz", 1)
z.setdefault("zzz", 2)
z.setdefault("z", -100)
z
# {'z': 0, 'zz': 1, 'zzz': 2}

dict.update(dict): dict に対して引数に指定した dict を結合します.キーが重複する場合は,引数に指定したキーの値で上書きされます.

x = {"00": 0, "01": 1, "02": 2}
y = {"00": "00", "001": 1, "02": 20}
x.update(y)
x
# {'00': '00', '01': 1, '02': 20, '001': 1}

dict.pop(key): dict から key とその値を削除します.注意として,この操作は,削除対象の要素を返します.

a = {"a": 0, "b": 1, "c": 2}
popped = a.pop("a")
popped, a
# (0, {'b': 1, 'c': 2})

dict.popitem(): dict からキーと要素のペアを削除します.この操作は,削除対象のキーと値のペアをタプルで返します.注意として,削除するペアを選択することはできません.

a = {"a": 0, "b": 1, "c": 2}
popped = a.popitem()
popped, a
# (('c', 2), {'a': 0, 'b': 1})

dict.clear(): dict から要素をすべて削除します.

a = {"a": 0, "b": 1, "c": 2}
a.clear()
a
# {}

dict.copy(): dict のコピーを生成します.

a = {"a": 0, "b": 1, "c": 2}
b = a.copy()
b
# {'a': 0, 'b': 1, 'c': 2}

a == b
# True

以下の通りアンパックも可能で,メソッド無しの場合は .keys() メソッドと同様にキーが返されますが,可読性の観点から .keys() と明示した方が良いでしょう.

a = {"a": 0, "b": 1, "c": 2}
aa, ab, ac = a
aa, ab, ac
# ('a', 'b', 'c')

aa, ab, ac = a.keys()
aa, ab, ac
#('a', 'b', 'c')

aa, ab, ac = a.values()
aa, ab, ac
# (0, 1, 2)

del dict(key) とすることで,dict から指定したキーと値のペアを削除することもできます.

a = {"a": 0, "b": 1, "c": 2}
del a["b"], a["c"]
a
# {'a': 0}

Python のおすすめの学習方法

プログラミングを最短で習得する,少なくても自分の意志で使えるようになる方法について,いくつかプログラミング言語を触ってきた筆者としては何の言語においても,以下2点が重要だと思います.

  • 元々自分が他の言語で作っていた処理を違う言語で書き直す・・・・英語を勉強するときも,脳を生まれたばかりのまっさらな状態から勉強するわけではなく,日本語を通したり対比して,学習済みの言語野を用いて勉強するのと似ています
  • 言語自体を網羅的に勉強するのではなく,やりたい事を先に考え,それを達成するために色々と調べながら実装する・・・・例えば,留学で語学力が上達するのは,その国の言葉を使ってコミュニケーションを取ることが強制されるためであり,使うことに対するモチベーションが一番大事です

独学で行うには,やはり2点目の「やりたい事ドリブン学習」が効果的で,例えば次の書籍は,Python を流行らせている AI/データ分析/機械学習/深層学習について実装することに主眼を置き説明されているので,実際に手を動かしながら学んでいける本だと思います(筆者も最初にこちらの書籍で遊びながら学びました).

コメント

タイトルとURLをコピーしました