コンテンツにスキップ

Python/

出典: フリー教科書『ウィキブックス(Wikibooks)』

Pythonは高水準の汎用プログラミング言語です。 Pythonの設計思想はコードの読みやすさに重点を置いています。 その構造に対するアプローチは独特であり、例えば、ブロックは波括弧 { } ではなくインデントで構造化されています。

また、Pythonはオブジェクト指向、インタプリタ、動的コーディング、クロスプラットフォームのプログラミング言語です。 これらのアプローチは、プログラマが小規模なプロジェクトから大規模なプロジェクトまで、自明で論理的なコードを書くことができるようにすることを目的としています。


基本事項

[編集]

開発環境の構築

[編集]

Pythonのインストールと基本的な利用

[編集]

Pythonは、Unix、GNU/Linuxのディストリビューション、およびmacOSでは通常最初からインストールされていますが、他のオペレーティングシステムでは初めて利用する際には手動でのインストールが必要です。

GNU/Linux環境

[編集]

GNU/Linuxデスクトップ環境では、コマンドターミナルを開き、以下のコマンドを実行することでPythonのインタープリタを起動できます。コマンド名はpythonの様にバージョンを含んでいないかもしれません。

$ python3
Python 3.12.2 (main, Feb  7 2024, 20:47:03) [GCC 13.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

これにより、Pythonの対話モードが開始され、プロンプトが「>>>」に変わります。ここでPythonコードを実行したり、インタラクティブに作業することができます。終了するには、「exit()」と入力します。

>>> exit()

Windows環境でのPythonのプログラミング

[編集]
公式配布版Pythonインストーラの使用
  1. Python公式サイトから公式配布版Pythonインストーラをダウンロードします。
  2. ダウンロードしたインストーラを実行し、指示に従ってPythonをインストールします。
Microsoft Storeからの導入
  1. Microsoft Storeを開き、検索バーに「Python」と入力します。
  2. Pythonの公式アプリケーションを見つけ、インストールします。

これらの方法でPythonをWindowsに導入することができます。インストールが完了したら、コマンドプロンプトやPowerShellからPythonを実行できるようになります。Pythonのバージョンや依存関係などについては、公式ドキュメントを参照することができます。

Pythonの実行方法

[編集]

Pythonを実行する方法には、主に2つのアプローチがあります。

インタラクティブモードでの実行方法

[編集]

インタラクティブモード(REPL: Read-Eval-Print Loop)では、Pythonのコマンドを1行ずつ入力して実行することができます。以下は、インタラクティブモードでの実行手順です。

  1. ターミナルを開きます。
  2. Pythonのコマンド(pythonまたはpython3など、環境によって異なる可能性があります)を入力します。
  3. ">>>"プロンプトが表示され、Pythonのコマンドを1行ずつ入力して実行します。例えば、"print('Hello World')"と入力すると、"Hello World"と出力されます。
$ python3
Python 3.11.7 (main, Dec  8 2023, 14:22:46) [GCC 13.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> print("Hello world")
Hello world
>>> exit()
$ _


ソースファイルを作成して実行する方法

[編集]

ソースファイルを作成して実行する場合は、以下の手順を参考にしてください。

  1. テキストエディタを開きます。
  2. Pythonのプログラムを入力し、ファイル名を"*.py"で保存します(例:"hello.py")。
  3. ターミナルを開き、以下のコマンドを入力します(pythonの代わりにpython3を使用することもあります)。
    $ python ファイル名.py
    
  4. ソースファイルが実行されます。例えば、以下のようなPythonプログラムを"hello.py"というファイル名で保存し、実行する場合は以下のコマンドを入力します。
    hello.py
    # hello.py
    print("Hello World!")
    
    コマンドライン
    $ python hello.py
    Hello World!
    $ _
    

Pythonのソースファイルの拡張子は ".py" です。これらの手順を踏むことで、Pythonのプログラムを作成し、実行することができます。

ソースコードを書き換えてみる

[編集]

さきほどの「Hello World!」と表示するプログラムを実行した後、ソースコードを書き換えるとどうなるのでしょうか。

以下に具体的な手順を示します。

  1. まず、先程のプログラムを実行して「Hello World!」と表示されることを確認します。
  2. 次に、ソースコードのファイル「hello.py」をテキストエディタで開きます。
  3. ソースコードを以下のように書き換えます。
    print("12345Hello World")
    
  4. ソースコードを上書き保存します。
  5. コマンドターミナルで以下のコマンドを実行します。
    $ python3 hello.py
    12345Hello World
    $ _
    

つまり、ソースコードを書き換えてから再度実行すると、新しいソースコードが反映されてプログラムが実行されます。

Pythonはインタプリタ言語であるため、プログラムを実行するたびにソースコードを解釈し直す特性があります。これにより、柔軟かつ効果的にプログラムを開発・実行することが可能となります。

数値の計算

[編集]

Pythonでは、数値の四則演算が簡単に行えます。以下に、基本的な数値計算の例を示します。

>>> 2 + 3
5
>>> 6 + 7
13
>>> 30.6 + 7.1
37.7
>>> 5 - 4
1
>>> 23.88 - 7.5
16.38
>>> 2 - 15
-13
>>> 2 * 4
8
>>> 4 / 2
2.0
>>> 4 / 3
1.3333333333333333

インタラクティブ モードでは、コマンドターミナルでPythonを起動し、コマンドラインで1行ずつコードを入力することができます。数値の計算も同様に行えます。

また、整数と浮動小数点数を足したり引いたりする場合、Pythonは自動的に浮動小数点数に変換して計算します。例えば、「2 + 1.5」という計算では、整数の2が自動的に浮動小数点数の2.0に変換されて計算されます。

>>> 2 + 1.5
3.5

Pythonでは、割り算の商だけを求めたい場合、「//」演算子を使用します。これにより、小数点以下を切り捨てて整数部分の商を得ることができます。

>>> 10 // 3
3
>>> -10 // 3
-4

実数の割り算を行う場合は、「/」演算子を使用します。

>>> 10 / 3
3.3333333333333335

べき乗演算を行うための「**」演算子もあります。例えば、「2**3」という計算は2の3乗を表し、結果として「8」が得られます。

>>> 2**3
8

また、「2**-3」という計算は2の-3乗を表し、逆数の計算をして「0.125」が得られます。

>>> 2**3
8

さらに、「(-2)**0.5」という計算は-2の0.5乗を表し虚数項を含んだ複素数が得られます。

>>> (-2)**0.5
(8.659560562354934e-17+1.4142135623730951j)

この計算結果に見られる 8.659560562354934e-17 は、計算誤差によるものです。Pythonの浮動小数点数演算は、厳密な数値表現が難しいため、微小な誤差が生じることがあります。

ここでの e-17 は、10のマイナス17乗を表しています。つまり、非常に小さな値であることを示しています。この誤差は計算機が二進数で浮動小数点数を表現する都合上生じるもので、数学的な理想値と実際の計算結果が微妙に異なることがあります。

これは浮動小数点数の特性であり、計算機が十進法ではなく二進法で数値を表現するために生じるものです。通常、このような微小な誤差は考慮範囲内とされ、数値計算において許容される範囲です。


これらの演算子を活用することで、様々な数値計算をPythonで効率的に行うことができます。

3項以上の計算

[編集]

Pythonでは、3項以上の計算も可能です。複雑な計算式を書く場合は、演算の優先順位に注意が必要です。たとえば、「2 + 3 * 4」という式を計算する場合、「3 * 4」が先に計算されてから、「2 + 12」が計算されます。結果として、「14」という値が得られます。

>>> 2 + 3 * 4
14

演算子には、優先順位を決める規則がありますが、括弧を使用することで、明示的に優先順位を指定することもできます。例えば、「(2 + 3) * 4」では、括弧内が先に計算されてから全体が掛け算されます。

>>> (2 + 3) * 4
20

このように、括弧を使用することで計算の順序を明確にし、意図した結果を得ることができます。複雑な式や優先順位のわからない場合は、括弧を使用して計算順序を明示的に指定すると良いでしょう。

同じ優先度の演算子が連続して使用される場合、Pythonでは左結合(左から右に結合)が行われます。これは多くのプログラミング言語で採用されている結合方向の一つです。

例えば、次のような計算を考えます。

>>> 5 * 3 / 2
7.5

この場合、掛け算と割り算の演算子の優先度は同じですが、左結合のため、左から順に計算されます。具体的には、まず「5 * 3」が計算されてからその結果を「2」で割ります。結果として 7.5 が得られます。

同様に、次の例では加算と減算が同じ優先度の演算子ですが、左結合により左から順に計算されます。

>>> 10 - 5 + 3
8

具体的には、まず「10 - 5」が計算されてからその結果に「3」が加算されます。結果として 8 が得られます。

左結合は一般的な動作であり、数学的な式の記述と一致しているため、多くの場面で直感的に使える結合方向です。



変数と代入

[編集]

変数とは

[編集]

Pythonにおける変数は、値に対して名前(または識別子)を付けたものです。変数を定義するには、単に変数名を使って値を代入します。以下は例です:

my_variable = 42

この例では、my_variable という変数に整数の値 42 が代入されています。変数は値を格納するだけでなく、後でその値を変更することもできます。

Pythonの変数には型がありません。つまり、変数自体には整数、文字列、リストなどの特定の型が割り当てられるのではなく、変数が保持する値がその型を持っています。これにより、同じ変数が異なる型の値になることが可能です。

my_variable = 42  # 整数型
my_variable = "Hello, World!"  # 文字列型

このように、同じ変数が異なる型の値に変わることを「動的型付け」と呼びます。変数が保持する値の型は、実行時に決定されます。

変数を使うことで、データや計算結果を記憶し、再利用することができます。変数名は意味を持たせ、コードの可読性を向上させるために工夫されることが一般的です。

変数と参照

[編集]

変数と参照について理解するためには、Pythonにおける変数の動作について知ることが重要です。

  1. 変数の定義: 変数は値に対して名前を付けるものであり、代入によって値を変数に紐付けます。例えば:
    x = 42
    
    この場合、変数 x は整数値 42 を参照しています。
  2. 変数の参照: 変数はその値を保持するのではなく、値への参照を保持します。変数を使って値を取得したり変更したりするとき、実際にはその値への参照を操作しています。
    y = x  # yはxと同じ値を参照
    
    この場合、yx と同じ値を参照しています。これは、y に変更が加えられても x にも同様の変更が影響する可能性があります。
  3. オブジェクトの参照: Pythonでは全てがオブジェクトです。変数はオブジェクトへの参照を持ちます。例えば、リストや文字列もオブジェクトです。
    list_a = [1, 2, 3]
    list_b = list_a  # list_bはlist_aと同じリストを参照
    
    ここで、list_blist_a と同じリストを参照しており、片方のリストを変更するともう一方にも影響します。
  4. 変更可能なオブジェクトと不変なオブジェクト: リストや辞書などの変更可能なオブジェクトは、その値が変更されると変更が反映されます。しかし、整数や文字列などの不変なオブジェクトは変更できません。
    immutable_value = 42
    mutable_list = [1, 2, 3]
    
    immutable_value = 99  # 新しい値に変更
    mutable_list.append(4)  # リストに要素を追加
    
    immutable_value の変更は新しい値に変わりますが、mutable_list の変更は元のリストに影響を与えます。

理解の鍵は、変数は値を持たず、値への参照を持つという点です。これにより、変数同士が同じオブジェクトを共有することができ、一方の変数を通じてオブジェクトが変更されると他方の変数にも変更が反映される可能性があります。

[編集]

Pythonにはさまざまなデータ型が組み込まれています。以下は主なデータ型の一部です:

# 整数型 (int):
# 整数を表すための型です。例えば:
x = 5

# 浮動小数点型 (float):
# 小数点を持つ実数を表すための型です。例えば:
y = 3.14

# 文字列型 (str):
# 文字列を表すための型で、シングルクォート (') またはダブルクォート (") で囲まれたテキストです。例えば:
name = "John"

# リスト型 (list):
# 複数の要素を順序付きで格納するための型です。例えば:
numbers = [1, 2, 3, 4, 5]

# タプル型 (tuple):
# リストと似ていますが、不変 (immutable) な型で、要素の変更ができません。例えば:
coordinates = (3, 4)

# 辞書型 (dict):
# キーと値のペアを格納するための型で、連想配列とも呼ばれます。例えば:
person = {"name": "Alice", "age": 30, "city": "Wonderland"}

# 集合型 (set):
# 重複のない要素の集まりを表すための型です。例えば:
unique_numbers = {1, 2, 3, 4, 5}

# ブール型 (bool):
# 真 (True) または偽 (False) の値を持つ型です。条件分岐や論理演算で使用されます。例えば:
is_adult = True

変数には型がなくオブジェクトに型がある

[編集]

type()関数を使用すると、変数や値の型を取得できます。これを使って先程の例を確認してみましょう。

x = 5
y = "Hello"
z = 3.14

print(type(x))  # <class 'int'>
print(type(y))  # <class 'str'>
print(type(z))  # <class 'float'>

ここでtype()関数は、変数や値の型を返します。xは整数型 (int)、yは文字列型 (str)、zは浮動小数点数型 (float) です。

同じ変数に異なる型の値を代入する場合にも、type()を使用して型の変化を確認できます。

z = 3.14
print(type(z))  # <class 'float'>

z = "World"
print(type(z))  # <class 'str'>

ここでzは最初にfloat型を持ち、後でstr型に変化しています。

代入

[編集]

Pythonにおける代入は、左辺の識別子に右辺のオブジェクトをバインド(結びつけ)する操作です。これは、変数が特定の値やオブジェクトを参照する仕組みを表しています。

例えば、以下のコードを考えましょう:

x = 5

この場合、xという識別子(変数)に整数型のオブジェクト 5 がバインドされています。このバインディングにより、xを通じて 5 にアクセスできます。

また、代入によって同じオブジェクトが複数の識別子にバインドされることもあります。例えば:

a = [1, 2, 3]
b = a

ここで、abは同じリストオブジェクトを参照しています。これは、リストなどの変更可能な(mutable)オブジェクトが変数を介して変更されると、その変更が他の変数にも反映されるためです。

変数には意味のある名前をつけましょう

[編集]

変数には意味のある名前を付けることは、コードの可読性を向上させ、保守性を高めます。意味のある名前を使うことで、コードを読んだりメンテナンスしたりする際に変数が表す内容や目的が明確になります。 例えば:

age = 25  # 年齢を表す変数名
name = "Alice"  # 名前を表す変数名
user_list = [1, 2, 3]  # ユーザーのリストを表す変数名

これらの変数名は、それぞれの変数が何を表しているかをわかりやすく示しています。コードが複雑になると、意味のある名前が特に重要です。

ただし、名前があまりにも長すぎたり複雑すぎたりすると、逆にコードの読みやすさを損なうことがあります。バランスを取りながら、適切な名前を選ぶことが重要です。

識別子とキーワード

[編集]

識別子

[編集]

識別子(Identifiers)は、Pythonで変数、関数、クラス、モジュールなどに付ける名前を指します。Pythonの識別子にはいくつかのルールがあります:

  1. 識別子は英字またはアンダースコア(_)で始まる必要があります。
  2. その後には英数字またはアンダースコアを含めることができます。
  3. 大文字と小文字は区別されます。
  4. Pythonのキーワード(後述)は使用できません。

以下は、識別子の例です:

my_variable = 42
user_name = "John"
calculate_sum = lambda x, y: x + y

これらの例では、それぞれ変数、変数、関数に使用されている識別子です。適切で意味のある名前を使い、コードを読みやすくするために、識別子には十分な注意が払われるべきです。

識別子に使えるASCII範囲外の文字

[編集]

Python 3.0からはASCII範囲外の文字の一部も識別子に使用できるようになりました。これにはUnicode文字も含まれます。具体的には、以下の種類の文字が使えます:

  • Lu - uppercase letters - 大文字
  • Ll - lowercase letters - 小文字
  • Lt - titlecase letters - 表題文字
  • Lm - modifier letters - 擬似文字
  • Lo - other letters - その他の文字(漢字はここ)
  • Nl - letter numbers - 数値を表す文字
  • Mn - nonspacing marks - 幅なし記号
  • Mc - spacing combining marks - 幅あり結合記号
  • Nd - decimal numbers - 十進数数字
  • Pc - connector punctuations - 連結句記号
  • Other_ID_Start - Unicode標準のプロパティリストに明示的にリストされた文字
  • Other_ID_Continue - 同上

ただし、この拡張を使用する際には、表示や編集の問題、正規化に関する問題に注意する必要があります。通常、ASCIIの範囲内に収める方が適切ですが、国際化や特定の文脈で必要な場合にはこの機能を活用することができます。

キーワード

[編集]

キーワード(Keywords)は、Pythonの構文規則の中に現れる特別なトークンで、識別子の様式に合致するにも関わらず、識別子には使用できない単語の集合です[1]。 次に示すキーワードは識別子には使用できません[2]

キーワードの一覧を表示するスクリプト
import keyword

print(' '.join(keyword.kwlist))
実行結果
False None True and as assert async await break class continue def del elif else except finally for from global if import in is lambda nonlocal not or pass raise return try while with yield

ソフト・キーワード

[編集]

Python 3.10 からは "ソフト・キーワード"(Soft keywords) として知られる概念が導入されました[3]。ソフト・キーワードは、通常のキーワードと同じく構文上特別な意味を持つが、一般の識別子としても利用できる単語です。Pythonでは、以下の単語がソフト・キーワードとして扱われます:

  • case
  • match
  • _

これらの単語は、通常のキーワードとして特別な文脈で使われる場合にはキーワードとして解釈されますが、一般のコードの中で普通の識別子としても利用できます。これは、特にパターン・マッチング関連の新しい機能をサポートするために導入されました。

予約済み識別子クラス

[編集]

予約済み識別子クラス(Reserved classes of identifiers)[4]は、キーワードやソフト・キーワード以外の識別子で特別な意味を持つものです[5]。 予約済み識別子クラスは、先頭と末尾のアンダースコア文字のパターンによって識別されます。

_*
from module import * でインポートされていません。
_
match文の中のcaseパターンでは、_はワイルドカードを表すソフトキーワードです。
これとは別に、対話型インタープリタでは、最後に評価した結果を変数 _ に格納して利用できるようにしています(これは、print などの組み込み関数と一緒に builtins モジュールに格納されています)。
その他の場所では,_は通常の識別子です.これはしばしば「特別な」アイテムの名前に使われますが、Python自体にとっては特別なものではありません。
Note
_ はしばしば国際化に関連して使用されます。この慣習についての詳細は gettext モジュールのドキュメントを参照してください。
また、使われていない変数にもよく使われます。
__*__
システムで定義された名前で、非公式には "dunder "名として知られています。これらの名前は、インタープリタとその実装(標準ライブラリを含む)によって定義されます。現在のシステム名については、「特別なメソッド名」のセクションなどで説明しています。Pythonの将来のバージョンでは、さらに多くの名前が定義されるでしょう。明示的に文書化された使用方法に従わない、いかなる文脈での __*__ 名の使用も、警告なしに破壊される可能性があります。
__*
クラスプライベートな名前です。このカテゴリの名前は、クラス定義の文脈の中で使用された場合、基底クラスと派生クラスの "private "属性の間の名前の衝突を避けるために、マングルされたフォームを使用するように書き直されます。

アトム

[編集]

アトムは、式の最も基本的な要素です。最も単純なアトムは、識別子またはリテラルです。括弧や大括弧、中括弧で囲まれた形式も、構文上はアトムに分類されます[6]

識別子(名前)

[編集]

アトムとして出現する識別子は名前です[7]

名前がオブジェクトにバインドされている場合、アトムを評価するとそのオブジェクトが得られます。名前がバインドされていない場合、評価しようとすると NameError という例外が発生します。

プライベート名のマングリング。
クラス定義に含まれる識別子が、2つ以上のアンダースコアで始まり、2つ以上のアンダースコアで終わらない場合、そのクラスのプライベート名とみなされます。プライベート・ネームは、コードが生成される前に長い形式に変換されます。この変換では、クラス名の前に、先頭のアンダースコアを削除し、1つのアンダースコアを挿入します。例えば、Hamという名前のクラスで発生した識別子__spamは、_Ham__spamに変換されます。この変換は、識別子が使用されている構文上の文脈とは関係ありません。変換後の名前が極端に長い(255文字以上)場合は、実装で定義された切り捨てが行われることがあります。クラス名がアンダースコアだけで構成されている場合、変換は行われません。

組込み関数や、組込み型はキーワードではありません

[編集]

組込み関数(例えば print)や、組込み型(例えば int)はキーワードではありません。 キーワードではありませんが、迂闊に組込み関数や組込み型と同じ名前の変数や関数を定義すると、次から関数が使えなくなります。 回避方法はあります。

コード例
p=print
print=123
p(print)
実行結果
123
printを123で代入し参照不能に陥る前に、pに(実行結果でなく)print関数を代入しています。
関数呼び出しは、保存した p を介して行っています。

回避方法はあるものの、読んだヒト[8]が混乱するので組込み関数や型と重複した識別子は使わないように心がけましょう。


参考文献

[編集]


数値入力と文字入力と出力表示

[編集]

入力

[編集]

文字列の入力

[編集]

Pythonで文字列の入力は、input() 関数を使用します。以下は、文字列を入力して表示する簡単な例です。

# 文字列の入力例
user_input = input("文字列を入力してください: ")

# 入力を表示
print("入力された文字列は:", user_input)

このコードでは、input() 関数を使ってユーザーに文字列の入力を求め、その結果を変数 user_input に格納しています。そして、print() 関数を使ってその入力を表示しています。

上記のコードを実行すると、プログラムはユーザーに対話的に文字列を尋ね、入力された文字列を表示します。

もしユーザーが Ctrl + D(UNIX系システム)または Ctrl + Z(Windows)を入力してEOFを発生させると、EOFError が発生します。

EOF(End of File)をハンドルするためには、try-except ブロックを使用して、EOFError をキャッチすることができます。以下はその例です。

try:
    # 文字列の入力例
    user_input = input("文字列を入力してください: ")

    # 入力を表示
    print("入力された文字列は:", user_input)

except EOFError:
    print("EOFError: 入力が終了しました。")

このコードでは、try ブロック内で input() 関数を使ってユーザーに文字列の入力を求めています。もし EOFError が発生すると、それを except ブロックでキャッチして処理します。

これにより、ユーザーが入力を終了させたときにエラーが発生する代わりに、プログラムが graceful に終了します。

数値の入力と計算

[編集]

では、数値を入力させて、計算をさせたい場合、どうすればい良いのでしょうか?

文字列から整数への変換し計算し表示する
[編集]

文字列から整数への変換と計算を行うためには、int() 関数を使って文字列を整数に変換し、その後に計算を行います。以下はその例です。

# 文字列の入力例
user_input = input("整数を入力してください: ")

try:
    # 文字列を整数に変換
    number = int(user_input)

    # 計算と表示
    result = number * 2
    print(f"入力された整数の2倍は: {result}")

except ValueError:
    print("ValueError: 整数以外が入力されました。")
except EOFError:
    print("EOFError: 入力が終了しました。")

このコードでは、まず input() 関数を使ってユーザーに整数の入力を求め、int() 関数でその文字列を整数に変換します。変換が成功すれば、計算と結果の表示を行います。もし "abc" のような整数以外の文字列が入力された場合は、ValueError が発生し、それを except ブロックでキャッチしてエラーメッセージを表示します。また、EOFが発生した場合も except EOFError ブロックで処理しています。

文字列から浮動小数点数への変換し計算し表示する
[編集]

文字列から浮動小数点数への変換と計算を行うためには、float() 関数を使って文字列を浮動小数点数に変換し、その後に計算を行います。以下はその例です。

# 文字列の入力例
user_input = input("浮動小数点数を入力してください: ")

try:
    # 文字列を浮動小数点数に変換
    number = float(user_input)

    # 計算と表示
    result = number * 2.5  # 例として2.5倍にしますが、任意の計算が可能です
    print(f"入力された浮動小数点数の2.5倍は: {result}")

except ValueError:
    print("ValueError: 数値以外が入力されました。")
except EOFError:
    print("EOFError: 入力が終了しました。")

このコードでは、まず input() 関数を使ってユーザーに浮動小数点数の入力を求め、float() 関数でその文字列を浮動小数点数に変換します。変換が成功すれば、計算と結果の表示を行います。もし数値以外の文字列が入力された場合は、ValueError が発生し、それを except ブロックでキャッチしてエラーメッセージを表示します。また、EOFが発生した場合も except EOFError ブロックで処理しています。

変数と文字列を同時に表示したい場合

[編集]

Pythonでは、複数の変数や文字列を同時に表示するためには、print() 関数に複数の引数を渡すことができます。以下はその例です。

# 変数の定義
name = "John"
age = 30

# 変数と文字列を同時に表示
print("名前:", name, "年齢:", age)
実行結果
:
名前: John 年齢: 30

このコードでは、print() 関数に複数の引数を渡しています。各引数は,(カンマ)で区切られており、それぞれが表示される際にはスペースで区切られます。このようにして複数の変数や文字列を同時に表示することができます。

フォーマット済み文字列リテラル

[編集]

Python には文字列の中に式を埋込み文字列化する「フォーマット済み文字列リテラル(Formatted string literals; F文字列とも)」があります[9]

 print(f"文字列の中に{  }を埋め込むことができる")

のように、fを引用符の前につける事で利用できます。 引用符は二重引用符でも一重引用符でも、どちらでも構いません(ただし、引用符の開始と終始における引用符の種類は一致している必要があります。)。 JavaScriptなどの「テンプレート・リテラル」に相当する機能です[10]

コード例
x = 123

print(f"数は{x+100} です")
実行結果
数は223 です

F文字列は Pyhon3.6 から導入されました。Python2.x系では利用できません[11]

'{' と '}' 自身の文字列中での使用

[編集]

場合によってはテンプレートリテラルを使いつつも '{' や '}' 自身を文字列中で使用したい場合があります。 その場合は、'{' は '{{'、'}' は '}}' と二重にします。

コード例
x = 123

print(f"文字列{{x}} には {x} が代入されます")
実行結果
文字列{x} には 123 が代入されます

{式=} :式と値の双方の文字列化

[編集]

式の後に等号'='を付けることで式のテキストと評価後の値の両方を文字列化することができます。

コード例
x = 123

print(f"式と値の表示:{x=}")
print(f"式と値の表示:{[x * 2 for x in range(5)]=}")
print(f'''\
+++
{x=}
***
{[x * 2 for x in range(5)]=}
''')
実行結果
式と値の表示:x=123
式と値の表示:[x * 2 for x in range(5)]=[0, 2, 4, 6, 8]
+++
x=123
***
[x * 2 for x in range(5)]=[0, 2, 4, 6, 8]
''' から ''' あるいは、""" から """ はヒアドキュメントで、複数行に渡る文字列を表現できます。
ヒアドキュメントに f あるいは F を前置すると、Fヒアドキュメントになり、式の埋め込みができます。
開始を、 '''\ の様に \ を後置すると最初の改行を抑止できます。

Pythonの文字列フーマッティングの歴史

[編集]

文字列の%演算子

[編集]

最初に、文字列の % 演算子がありました。

x = 333

print('数は %s です' % x )
実行結果
数は 333 です

文字列のformatメソッド

[編集]

次に、文字列のformatメソッドができました[12]

x = 200

print('数は{y} です'.format(y=x) )
実行結果
数は200 です

脚註

[編集]
  1. ^ keyword — Testing for Python keywords” (2021年11月29日).テンプレート:Cite web/error
  2. ^ 3.10.0 Documentation » The Python Language Reference » 2. Lexical analysis§2.3.1. Keywords” (2021年11月29日).テンプレート:Cite web/error
  3. ^ 3.10.0 Documentation » The Python Language Reference » 2. Lexical analysis§2.3.2. Soft Keywords” (2021年11月29日).テンプレート:Cite web/error
  4. ^ Reserved classes of identifiersを「予約済み識別子クラス」と訳しました。ここで言うクラスはオブジェクト指向プログラミングでいう Class ではなく階級や種類という一般的普遍的な意味のクラスです。
  5. ^ 3.10.0 Documentation » The Python Language Reference » 2. Lexical analysis§2.3.3. Reserved classes of identifiers” (2021年11月29日).テンプレート:Cite web/error
  6. ^ 3.10.0 Documentation » The Python Language Reference » 6. Expressions§6.2. Atoms” (2021年11月29日).テンプレート:Cite web/error
  7. ^ 3.10.0 Documentation » The Python Language Reference » 6. Expressions§6.2.1. Identifiers (Names)” (2021年11月29日).テンプレート:Cite web/error
  8. ^ 将来のあなたかもしれません。
  9. ^ Lexical analysis # Formatted string literals” (2021年11月29日). 2021年11月29日閲覧。
  10. ^ JavaScriptのテンプレート・リテラルはヒアドキュメントの機能も持っています。
  11. ^ Python2.x系のサポートは2021/01/01に終了しました。 ⇒ PEP 373 -- Python 2.7 Release Schedule, PEP 404 -- Python 2.8 Un-release Schedule
  12. ^ PEP 3101 -- Advanced String Formatting


条件分岐と繰り返し

[編集]

Python の制御構造には、逐次・分岐・繰返しの3つがあり。このうち逐次はプログラムが左上から左から右・上から下に進む当たり前の状態ですので、これ以上の説明は必要ないと思います[1]

条件分岐

[編集]

Pythonでは条件分岐をするために if 文あるいは match 文を使います。

if文

[編集]

Pythonでは条件分岐をするために if 文を使います[2]。基本的な形は以下のようになります:

if 条件:
    条件が真の場合に実行されるコード
elif 別の条件:
    別の条件が真の場合に実行されるコード
else:
    どの条件も満たされない場合に実行されるコード

例えば、ある変数 x の値に基づいて条件分岐する場合を考えてみましょう:

x = 10

if x > 10:
    print("xは10より大きいです")
elif x < 10:
    print("xは10より小さいです")
else:
    print("xは10です")

この場合、x の値が10なので、最初の条件と最後の条件のどちらも満たされますが、最初の条件が先に評価されます。そのため、"xは10です" と出力されます。

条件分岐を使うことで、プログラムが特定の条件下で異なる動作をするように制御することができます。

match 文

[編集]

Python 3.10以降では、match文が導入されました[3]。match文は、特定の値に基づいてパターンをマッチングし、対応するブロックを実行するのに使用されます。match文は、複数の値や条件を一度に比較し、コードをより読みやすくし、処理をシンプルにするのに役立ちます。

以下は、match文の基本的な使い方です:

def check_value(x):
    match x:
        case 1:
            print("xは1です")
        case 2:
            print("xは2です")
        case _:
            print("その他の値です")

この例では、x の値に応じて異なる処理を行います。match文では、caseキーワードを使用して値やパターンを指定し、そのパターンがマッチした場合に対応するブロックが実行されます。また、case _:のように_を使用することで、どのケースにもマッチしない残りのケースを処理することができます。

さらに、match文では複数の条件やパターンをまとめて処理することもできます。例えば、タプルやリスト、または|演算子を使用して複数の条件を指定できます:

def check_pair(pair):
    match pair:
        case (0, 0):
            print("原点です")
        case (x, y) if x == y:
            print("xとyは同じ値です")
        case (x, _) if x > 0:
            print("xは正の値です")
        case _:
            print("その他のケースです")

この例では、(0, 0)ならば原点、(x, y)でxとyが同じなら同じ値、(x, _)でxが正の値なら正の値、それ以外のケースを処理します。

match文はパターンマッチングを使用して柔軟な条件分岐を行うのに役立ちます。これにより、コードの読みやすさと保守性を向上させることができます。

条件式

[編集]

条件式はプログラミングで特定の条件が成立するかどうかを判定するために使われます。Pythonでは、if文を使って条件式を評価し、条件が真である場合に特定のコードブロックを実行します。

基本的な構文は以下のようになります:

if 条件式:
    条件が真の場合に実行されるコード
else:
    条件が偽の場合に実行されるコード

elseは省略可能で、条件が偽の場合に何も実行しないようにすることができます。

比較演算子や論理演算子

[編集]

Pythonでは比較演算子や論理演算子を使って条件式を組み立てることができます。主な比較演算子は以下の通りです:

  • ==: 等しい
  • !=: 等しくない
  • <: より小さい
  • >: より大きい
  • <=: 以下
  • >=: 以上

例えば:

x = 5

if x == 5:
    print("xは5です")
else:
    print("xは5ではありません")
比較演算の特異な例
x = float("nan")

if x > 0.0:
    print("xは正の数です")
elif x < 0.0:
    print("xは負の数です")
elif x == 0.0:
    print("xは零です")
else:
    print(f"xは{x}です")
実行結果
xはnanです
nanってナニ?
唐突に float("nan")、が出てきましたが、これがPythonでNaN(Not a Number; 非数)を得る方法で、他には math を import して math.nan を使う方法もあります。

nan は、浮動小数点演算の結果として、不正なオペランドを与えられたために生じた結果を表す値またはシンボルで[4]、NaNの体系的仕様は、無限大の表現などと共に1985年の IEEE 754 浮動小数点規格で標準が与えられています。

nanの特徴
どんな値と比較しても不一致
nan 自身とも一致しないです( nan == nan ⇒ False )
どんな数学関数の引数に与えても結果は nan
nan であるかは is 演算子をつかう( nan is nan ⇒ True)
あるいは math を import し math.isnan(x) をつかう( isnan(nan) ⇒ True)

さらに、複数の条件を組み合わせるために論理演算子を使用できます:

  • and: 論理積(両方の条件が真である場合に真)
  • or: 論理和(どちらかの条件が真である場合に真)
  • not: 否定(条件の反対)

例えば:

x = 10
y = 5

if x > 5 and y < 10:
    print("xは5より大きく、yは10より小さいです")

このようにして、条件式を使うことでプログラム内で特定の条件が成立するかどうかを判断し、それに応じた処理を行うことができます。

複数の比較演算子の連結
上記の例では、and 演算子の説明のため
  • x > 5 and y < 10

としていますが、これは

  • 5 < x < 10

と書くこともできます。両者は同じ意味になりますがxの参照は後者は一度だけになります。

in 演算子

[編集]

in演算子はPythonで非常に便利な演算子の1つです。in演算子は特定の要素がコレクション(リスト、タプル、文字列など)に含まれているかどうかをチェックするのに使います。

例えば、リスト内に特定の要素が含まれているかを確認する場合に使えます:

my_list = [1, 2, 3, 4, 5]

if 3 in my_list:
    print("3はリスト内に含まれています")

同様に、文字列内で特定の部分文字列が存在するかを確認することもできます:

my_string = "Hello, World!"

if "Hello" in my_string:
    print("文字列内に'Hello'が含まれています")

in演算子は、リストや文字列の他にも、辞書や集合などのコレクションでの要素の存在をチェックするのに役立ちます。条件式にin演算子を使うことで、特定の要素がコレクションに含まれているかどうかを簡単に判断できます。

様々な型の論理値への変換

[編集]

Pythonの条件式では、整数、文字列、リストなどのさまざまなデータ型を使用することができます。条件式では、その値が真か偽かを判定します。

整数を条件式として使用する場合、0は偽として扱われ、0以外の整数は真として扱われます。例えば:

x = 5

if x:
    print("xは真です")
else:
    print("xは偽です")

ここでは、xが0以外の値(真)を持っているため、"xは真です"と出力されます。

文字列やリストなどのシーケンスも条件式として使用できます。空の文字列や空のリストは偽として扱われます。例えば:

my_string = ""
my_list = []

if my_string or my_list:
    print("空ではありません")
else:
    print("空です")

上記の場合、my_stringmy_listの両方が空なので、"空です"と出力されます。

このように、Pythonの条件式では値が真か偽かを判定し、それに基づいてコードを実行することができます。整数、文字列、リストなど、さまざまなデータ型を条件式として使用することで、柔軟な条件分岐を行うことができます。

if 式

[編集]

Pythonのif文は、条件に基づいてコードの実行を制御するためのものでしたが、Python3.8からはif式(または三項演算子)が導入されました。if式は、1行で条件に応じて値を返すことができます。

if式の基本的な構文は以下の通りです:

value_if_true if condition else value_if_false

これは、条件が真の場合にvalue_if_trueを返し、偽の場合にvalue_if_falseを返します。

例えば、次のように使えます:

x = 5
result = "Even" if x % 2 == 0 else "Odd"
print(result)

この場合、xが偶数なら"Even"が、奇数なら"Odd"が出力されます。

このように、if式を使うと簡潔に条件に応じて値を設定したり、返したりすることができます。特に、1行で簡潔に条件式を表現したい場合に便利です。

内包表記とif式

[編集]

内包表記とif式は、Pythonでコードを短く、効率的に書くための強力な機能です。

内包表記は、リスト、集合、辞書などのデータ構造を構築するための簡潔な方法です。if式を内包表記に組み込むことで、特定の条件を満たす要素のみを含むリストや集合を生成できます。

リスト内包表記でifを使う例を見てみましょう:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 偶数のみを含むリストを生成する
even_numbers = [x for x in numbers if x % 2 == 0]
print(even_numbers)

このコードでは、numbersリストから偶数のみを取り出してeven_numbersリストを生成しています。リスト内包表記の中でifを使用することで、条件に合致する要素だけを含むリストを作成できます。

同様に、辞書内包表記や集合内包表記でもif式を使用できます。例えば:

# 辞書内包表記で奇数とその2乗を辞書にする
odd_squares_dict = {x: x**2 for x in numbers if x % 2 != 0}
print(odd_squares_dict)

# 集合内包表記で偶数の集合を生成する
even_set = {x for x in numbers if x % 2 == 0}
print(even_set)

これらの例は、内包表記を使って条件に基づいてリスト、辞書、集合を生成する方法を示しています。if式を内包表記に組み込むことで、コンパクトで読みやすいコードを書くことができます。

match文

[編集]

Python 3.10 から、パターンマッチングを行う match 文がサポートされました[5]

正規表現の match メソッドとは別です。

match文を使った条件分岐
for x in range(10):
    print(x,"=", end=" ")
    match x:
        case 2:
            print('two')
        case 5:
            print('five')
        case 7:
            print('seven')
        case _:
            print('ELSE')
実行結果
0 = ELSE
1 = ELSE
2 = two
3 = ELSE
4 = ELSE
5 = five
6 = ELSE
7 = seven
8 = ELSE
9 = ELSE
_ は、ワイルドカードバターンで全てにマッチします。

match文は、2021年に導入された新しい機能で、3.9以前のバージョンのpythonではmatch文は使えません。

パターン

[編集]

Pythonの match 文で使用されるパターンは、以下のようなものがあります。

  • value パターン
  • ワイルドカード パターン
  • ガード パターン
  • type パターン
  • as パターン
  • or パターン
  • list パターン
  • tuple パターン
  • dict パターン
  • class パターン
  • シーケンス パターン

以下で、それぞれについて詳しく解説します。

value パターン

[編集]

value パターンは、値が等しいかどうかを比較するためのパターンです。以下は、例です。

match color:
    case "red":
        print("赤色です")
    case "blue":
        print("青色です")
    case "green":
        print("緑色です")

この例では、color という変数に格納された値に応じて、条件分岐を行っています。case "red": は、color"red" と等しい場合にマッチします。

ワイルドカード パターン

[編集]

ワイルドカードパターンは、どの値にもマッチするパターンです。ワイルドカードパターンは、_ という記号で表現します。

match value:
    case _:
        # valueがどの値にもマッチする場合の処理

ガード パターン

[編集]

ガードパターンは、条件式が True である場合にマッチするパターンです。ガードパターンは、if キーワードを使って表現します。

match value:
    case x if x > 0:
        # valueが0より大きい場合の処理
    case y if y < 0:
        # valueが0より小さい場合の処理
    ...

type パターン

[編集]

type パターンは、型が等しいかどうかを比較するためのパターンです。以下は、例です。

match value:
    case int:
        print("整数型です")
    case float:
        print("浮動小数点型です")
    case str:
        print("文字列型です")
    case _:
        print("不明な型です")

この例では、value という変数に格納された値の型に応じて、条件分岐を行っています。case int: は、value の型が整数型の場合にマッチします。

as パターン

[編集]

as パターンは、値を別名で参照するためのパターンです。以下は、例です。

match value:
    case int as n:
        print("整数型です。値は", n, "です")
    case float as f:
        print("浮動小数点型です。値は", f, "です")
    case str as s:
        print("文字列型です。値は", s, "です")
    case _:
        print("不明な型です")

この例では、value という変数に格納された値の型に応じて、条件分岐を行っています。case int as n: は、value の型が整数型の場合にマッチし、value の値を n という名前で参照することができます。

or パターン

[編集]

orパターンは、二つのパターンのいずれかにマッチする場合に使用されます。例えば、次のように使用します。

match x:
    case 0 or 1:
        print("x is either 0 or 1")
    case 2 or 3:
        print("x is either 2 or 3")
    case _:
        print("x is something else")

list パターン

[編集]

listパターンは、リストに対してマッチする場合に使用されます。次のように、リストの要素を一つ一つマッチングします。

match my_list:
    case [0, 1]:
        print("my_list is [0, 1]")
    case [2, 3]:
        print("my_list is [2, 3]")
    case [4, _, _]:
        print("my_list starts with 4 and has at least 3 elements")
    case _:
        print("my_list is something else")

tuple パターン

[編集]

tupleパターンは、タプルに対してマッチする場合に使用されます。リストの場合と同様に、タプルの要素を一つ一つマッチングします。

match my_tuple:
    case (0, 1):
        print("my_tuple is (0, 1)")
    case (2, 3):
        print("my_tuple is (2, 3)")
    case (4, _, _):
        print("my_tuple starts with 4 and has at least 3 elements")
    case _:
        print("my_tuple is something else")

dict パターン

[編集]

dictパターンは、辞書に対してマッチする場合に使用されます。次のように、辞書のキーと値を一つ一つマッチングします。

match my_dict:
    case {'a': 1, 'b': 2}:
        print("my_dict is {'a': 1, 'b': 2}")
    case {'c': 3, 'd': 4}:
        print("my_dict is {'c': 3, 'd': 4}")
    case {'e': 5, 'f': _}:
        print("my_dict has the key 'e' with the value 5 and the key 'f' with some other value")
    case _:
        print("my_dict is something else")

class パターン

[編集]

classパターンは、特定のクラスのインスタンスに対してマッチする場合に使用されます。次のように、クラス名を指定して、クラスのインスタンスにマッチングします。

class MyClass:
    def __init__(self, x, y):
        self.x = x
        self.y = y

match my_obj:
    case MyClass(0, 1):
        print("my_obj is an instance of MyClass with x=0 and y=1")
    case MyClass(2, 3):
        print("my_obj is an instance of MyClass with x=2

シーケンスパターン

[編集]

Pythonのシーケンスパターンは、リスト、タプル、文字列、バイト列のようなシーケンス型のデータをマッチングするために使用されます。シーケンスパターンは、複数の要素を一度にマッチングするために使用され、組み込みの結合演算子を使用して複数のパターンを結合することができます。

以下は、シーケンスパターンを使用してリストをマッチングする例です。

match my_list:
    case [1, 2, 3]:
        print("Matched [1, 2, 3]")
    case [1, _, _]:
        print("Matched [1, _, _]")
    case [1, *rest]:
        print("Matched [1, *rest]")
        print("rest =", rest)
    case _:
        print("Matched anything else")

上記の例では、my_listが4つの異なるパターンにマッチするように定義されています。最初のパターン [1, 2, 3]は、my_listが要素が1, 2, 3のリストである場合にマッチします。2番目のパターン [1, _, _]は、my_listが最初の要素が1で、次の2つの要素が何であってもマッチします。3番目のパターン [1, *rest]は、my_listが最初の要素が1である場合にマッチし、*restはリストの残りの部分をキャプチャします。最後のパターン _は、どのリストにもマッチするため、最後のパターンは常に True を返します。

シーケンスパターンは、パターンの部分を任意の式で置き換えることができるため、マッチングされた要素にアクセスして処理を実行することができます。例えば、以下の例ではリストの最初の2つの要素にアクセスしていることがわかります。

match my_list:
    case [x, y, *rest]:
        print("First two elements:", x, y)
        print("Rest of the list:", rest)

この例では、xyは最初の2つの要素を表し、restは残りのリストを表します。 rest はキーワードではありませんが、レストパターンを引き受ける変数の名前としてよく使われます。

連想配列を使った多方向分岐

[編集]

match文の最初の例は、辞書を使って下のように書き換えることができます。

辞書を使った例
h = { 2: "two", 5: "five", 7: "seven"}

for x in range(10) :
    print(f"{x} =", x in h and h[x] or "ELSE")

列挙型

[編集]

Python 3.4からは、enumモジュールが標準ライブラリとして提供されています[6]

以下は、enumパッケージを使用した簡単な例です。

from enum import Enum

class Color(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3

このように、Enumを継承したクラスを作成し、クラス属性として定数を定義することで、独自の列挙型を定義できます。 上記の例では、Colorという列挙型を定義し、REDGREENBLUEという3つの定数を定義しています。

列挙型を使用すると、例えばColor.REDというように、定数に直接アクセスすることができます。

print(Color.RED)   # Color.RED
print(Color.RED.name)  # RED
print(Color.RED.value)  # 1

また、列挙型はforループを使って列挙することができます。

for color in Color:
    print(color)

match文と組み合わせると、列挙型の値に基づいた処理を簡潔に記述できます。

match color:
    case Color.RED:
        print("Red color")
    case Color.GREEN:
        print("Green color")
    case Color.BLUE:
        print("Blue color")

Python 3.10以降では、enumパッケージにauto()という新しい機能が導入されました。これにより、列挙型に自動的に連番の値を割り当てることができます。

from enum import Enum, auto

class Color(Enum):
    RED = auto()
    GREEN = auto()
    BLUE = auto()

for color in Color:
    print(color.value)

上記のコードでは、auto()を使用して列挙型に自動的に連番の値を割り当てています。結果として、Color.REDは1、Color.GREENは2、Color.BLUEは3の値を持ちます。

まとめ
# Enumクラスのインポート方法
from enum import Enum

# 基本的な列挙型の定義方法
class MyEnum(Enum):
    VALUE1 = 1
    VALUE2 = 2
    VALUE3 = 3

# 名前と値の一覧を取得する
print(list(MyEnum))

# 特定の名前に対応する値を取得する
print(MyEnum.VALUE1.value)

# 名前からEnumオブジェクトを取得する
print(MyEnum['VALUE2'])

# 値からEnumオブジェクトを取得する
print(MyEnum(3))

# Enumクラスを比較する
class MyEnum(Enum):
    VALUE1 = 1
    VALUE2 = 2
    VALUE3 = 3

class MyOtherEnum(Enum):
    VALUE1 = 1
    VALUE2 = 2
    VALUE3 = 3

print(MyEnum.VALUE1 == MyOtherEnum.VALUE1)  # False
print(MyEnum.VALUE1 == MyEnum.VALUE1)        # True

# Enumクラスを継承して新しい列挙型を定義する
class MyExtendedEnum(MyEnum):
    VALUE4 = 4
    VALUE5 = 5

# Enumクラスによる自動値付け
from enum import Enum, auto

class MyAutoEnum(Enum):
    VALUE1 = auto()
    VALUE2 = auto()
    VALUE3 = auto()

print(MyAutoEnum.VALUE1.value)  # 1
print(MyAutoEnum.VALUE2.value)  # 2
print(MyAutoEnum.VALUE3.value)  # 3

繰返し

[編集]

Pythonには、さまざまな繰り返しの方法があります。主なものは for ループと while ループです。

for ループ:

[編集]

for ループは、リスト、タプル、辞書、集合などのイテラブル(要素を一つずつ取り出せるオブジェクト)を繰り返し処理するのに使います。

リストの例:

fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
    print(fruit)

fruitsリスト内の各要素を順番に取り出して、その要素をfruitという変数に格納してループ内で使用しています。

辞書の例:

person = {"name": "Alice", "age": 30, "city": "New York"}
for key, value in person.items():
    print(f"{key}: {value}")

items()メソッドを使って辞書のキーと値のペアを取得し、keyvalueにそれぞれ格納しています。

while ループ:

[編集]

while ループは指定された条件が真の間、繰り返し処理を実行します。

count = 0
while count < 5:
    print(count)
    count += 1

この例では、countが5未満の場合にループが実行され、countの値が表示されます。count += 1によってcountが1ずつ増加します。

:= 演算子

[編集]

:=演算子はPython 3.8で導入された「セイウチ演算子(Walrus operator)」として知られています。これは式内で変数に値を代入するためのもので、通常の代入文とif文を組み合わせたような構文を、より簡潔に記述できるようにします。

例えば、whileループでの使用方法を見てみましょう:

total = 0
while (input_value := int(input("Enter a number (0 to stop): "))) != 0:
    total += input_value

print(f"The total is: {total}")

この例では、input()関数を使ってユーザーから数値を入力し、:=演算子を使用して同時にinput_valueに代入しています。そして、入力された値が0でない限り、ループは継続され、totalに入力値を加算し続けます。入力された数値が0であればループは終了し、最終的な合計値が表示されます。

この演算子は、ループ内で変数を初めて定義する際や、式内で一時的な変数を使う場合などに特に便利です。ただし、適切に使うことでコードの読みやすさを損なわないように注意が必要です。

制御構造:

[編集]

breakcontinueなどの制御構造も使えます。breakはループを抜け出し、continueはループの現在のイテレーションをスキップして次のイテレーションに進みます。

for i in range(10):
    if i == 3:
        continue
    if i == 8:
        break
    print(i)

この例では、continueiが3のときに処理をスキップし、breakiが8のときにループを抜けます。

これらの方法を使って、Pythonで繰り返し処理を行う機能を活用することができます。

ループにつづくelse節

[編集]

while文あるいはfor文がbreak文で中断しなかった場合forにつづくelse節が実行されます。else節は、大概のプログラミング言語ではif文と組合わせて使いますが、Pythonではこれに加え繰返し(while文あるいはfor文)と組合わせることができます。

while+else

[編集]
while+else
i = 0
while i < 100:
    print(i, end=" ")
    i += 3
else:
    print("done!")

i = 0
while i < 100:
    if i > 10:
        break
    print(i, end=" ")
    i += 3
else:
    print("done!")
実行結果
0 3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 69 72 75 78 81 84 87 90 93 96 99 done!
0 3 6 9
ループを完走した場合は else 節を実行し、break (や return)で中断すると else 節は実行されません。
1つ目のwhileループは、変数iを0から3ずつ増やし、100以上になるまでループを繰り返します。ループの本体では、変数iの値を印刷します。end=" "は、印刷された各値の後に空白を追加し、すべてを1行に表示するためのものです。最後に、else節で"done!"というメッセージを印刷します。
2つ目のwhileループは、変数iを0から3ずつ増やし、10を超えるまでループを繰り返します。ループの本体では、変数iの値を印刷し、それが10を超えた場合は、breakステートメントが呼び出され、ループが終了します。最後に、else節が実行されず、"done!"というメッセージは印刷されません。
ループと結合したelseの使いどころ
Pythonでは、ループが完走したときに実行されるelse節を置くことができます。

では、このelse節は何に使うのでしょう?

1000以下の素数を求める(フラッグ版)
i = 2
while i <= 1000:
    j = 2
    is_prime = True
    while j * j <= i:
        if i % j == 0:
            is_prime = False
            break
        j += 1
    if is_prime:
        print(i, end=" ")
    i += 1
break で抜けたかをフラッグ is_prime で判断しています。
ゴチャゴチャしています。
1000以下の素数を求める(else版)
i = 2
while i <= 1000:
    j = 2
    while j * j <= i:
        if i % j == 0:
            break
        j += 1
    else:
        print(i, end=" ")
    i += 1
フラッグがなくなり簡素になりました。
1000以下の素数を求める(for+range版)
for i in range(2, 1000):
    for j in range(2, i):
        if i % j == 0:
            break
    else:
        print(i, end=" ")
こちらの方がより簡潔ですね。
while版と比べ内側のループが廻りすぎていますが(本来 sqrt(i)までで良い)、j2がなくなっているので1000までの区間なら性能劣化は軽微。
1000以下の素数を求める(素数集合更新版)
primes = []
for i in range(2, 1000):
    for prime in primes:
        if i % prime == 0:
            break
    else:
        primes.append(i)
        print(i, end=" ")
素数の集合を保持するリスト primes を導入しました
i の因数が primes になければ、iprimes に追加するロジックです
primes は素数が小さい順に保持されるので最も効率よく因数を探せます。

ループ完走のelseを使うと、「因数が見つからなかった」ケースをフラッグなしに表現でき、記述力が向上し、より洗練されたアルゴリズムの探求に貢献しています。 もし、素数集合更新版をフラッグで表現したら、これより遥かに記述性が劣るでしょう。

Python以外の言語では、Zigでも else を伴ったループ構文があります。

for+else

[編集]
for+else
h = {2: "two", 5: "five", 7: "seven"}

for x in list(h):
    print(h[x])
else:
    print("I didn't take a break.")

for x, v in h.items():
    if x == 7:
        break
    print(x, v)
else:
    print("I didn't take a break.")
実行結果
two
five
seven
I didn't take a break.
2 two
5 five
ループをカンストした場合は else 節を実行し、break (や return)で中断すると else 節は実行されません。
ループとelseを組合わせた大域脱出
Pythonはgoto分やラベル付きbreak文を持っていないので、大域脱出する場合は
  • ループ全体を関数にしてreturn文で脱出
  • tryをループをくくり例外をあげて脱出
  • プログラム自身を終了

などの工夫が必要です。

ここでは、ループと結合したelseを使った大域脱出を紹介します。

ループと結合したelseを使った大域脱出
for i in range(10):
    for j in range(10):
        for k in range(10):
            if (i == 2 and j == 3 and k == 5):
                break
            print(f"{i}{j}{k}", end=" ")
        else:
            print()
            continue
        break
    else:
        continue
    break
else:
    print("done!")
実行結果
000 001 002 003 004 005 006 007 008 009 
010 011 012 013 014 015 016 017 018 019 
020 021 022 023 024 025 026 027 028 029 
030 031 032 033 034 035 036 037 038 039 
040 041 042 043 044 045 046 047 048 049 
050 051 052 053 054 055 056 057 058 059 
060 061 062 063 064 065 066 067 068 069 
070 071 072 073 074 075 076 077 078 079 
080 081 082 083 084 085 086 087 088 089 
090 091 092 093 094 095 096 097 098 099 
100 101 102 103 104 105 106 107 108 109 
110 111 112 113 114 115 116 117 118 119 
120 121 122 123 124 125 126 127 128 129 
130 131 132 133 134 135 136 137 138 139 
140 141 142 143 144 145 146 147 148 149 
150 151 152 153 154 155 156 157 158 159 
160 161 162 163 164 165 166 167 168 169 
170 171 172 173 174 175 176 177 178 179 
180 181 182 183 184 185 186 187 188 189 
190 191 192 193 194 195 196 197 198 199 
200 201 202 203 204 205 206 207 208 209 
210 211 212 213 214 215 216 217 218 219 
220 221 222 223 224 225 226 227 228 229 
230 231 232 233 234
最外周のprint("done!")は(breakされた場合は)実行されません。

ループはスコープを作りません

[編集]

Pythonでは、ループはスコープを作りません。

ループはスコープを作りません
i = "abc"
j = "xyz"
print(f"forの前: {i=}{j=}")
for i in range(5):
    j = 2 * i
    print(f"forの中: {i=}{j=}")
print(f"forの後: {i=}{j=}")
実行結果
forの前: i='abc'、j='xyz'
forの中: i=0、j=0
forの中: i=1、j=2
forの中: i=2、j=4
forの中: i=3、j=6
forの中: i=4、j=8 
forの後: i=4、j=8

脚註

[編集]
  1. ^ 関数やメソッドの呼出しや復帰 return も制御構造と言えますが、本項では逐次・分岐・繰返しについて述べます。
  2. ^ 4.1. if Statements” (2024年1月6日). 2024年1月17日閲覧。
  3. ^ 4.1. if Statements” (2024年1月6日). 2024年1月17日閲覧。
  4. ^ ただし、Pythonでは math.asin(2) ↑ValueError であったりnanを返す前に例外が上がる事が多々あります。
  5. ^ 4.6. match Statements” (2021年11月17日). 2021年11月18日閲覧。
  6. ^ enum — Support for enumerations” (2021年11月17日). 2021年11月18日閲覧。

演算子

[編集]

式は、演算子と1項以上のオペランド(被演算子)からなります。 典型的には中置の二項演算子式ですが、単項演算子やif式のような式とは思い難い見た目をしているものもありますが、値を持つ構文要素はすべからく式と考えて構いません。

演算子の優先順位

[編集]

次の表は、Pythonにおける演算子の優先順位を、最も高い優先順位(最も拘束力が強い)から最も低い優先順位(最も拘束力が弱い)へとまとめたものです。同じ枠内の演算子は同じ優先順位を持ちます。構文が明示的に与えられていない限り、演算子は二項演算子です。同じボックス内の演算子は左から右へグループ化されます(右から左へグループ化される指数演算を除く)。

比較、メンバーシップテスト、同一性テストはすべて同じ優先順位を持ち、比較のセクションで説明したように、左から右へ連鎖する機能を持っていることに注意してください。

演算子の優先順位
演算子 概要
(expr...),[expr...], {key: value...}, {expr...} 結合式または括弧付き式、リスト、辞書、集合
x[index], x[start:stop:step], x(args...), x.attr 配列要素参照、スライス、関数やメソッドの呼出し、属性参照
await x Await 式
** 指数関数
+x, -x, ~x 単項プラス、単項マイナス、ビット単位のNOT
*, @, /, //, % 乗算、行列乗算、除算、剰余有除算、剰余
+, - 加算、減算
<<, >> シフト演算
& ビット単位の AND
^ ビット単位の XOR
<nowiki>|</nowiki> ビット単位の OR
in, not in, is, is not, <, <=, >, >=, !=, == メンバーシップテスト、アイデンティティテストなどの比較
not x ビット単位の NOT
and ビット単位の AND
or ビット単位の OR
ifelse 条件演算子
lambda ラムダ式
:= 代入演算子

演算子の一覧

[編集]
演算子の一覧
演算 構文 関数
加算 a + b add(a, b)
連結 seq1 + seq2 concat(seq1, seq2)
包含テスト obj in seq contains(seq, obj)
除算 a / b truediv(a, b)
除算 a // b floordiv(a, b)
ビット単位論理積 a & b and_(a, b)
ビット単位排他的論理和 a ^ b xor(a, b)
ビット反転 ~ a invert(a)
ビット単位論理和 <nowiki>a | b</nowiki> or_(a, b)
冪乗 a ** b pow(a, b)
同一性 a is b is_(a, b)
同一性 a is not b is_not(a, b)
インデックス指定代入 obj[k] = v setitem(obj, k, v)
インデックス指定削除 del obj[k] delitem(obj, k)
インデックス指定参照 obj[k] getitem(obj, k)
左シフト a << b lshift(a, b)
剰余 a % b mod(a, b)
乗算 a * b mul(a, b)
行列乗算 a @ b matmul(a, b)
算術否定 - a neg(a)
論理否定 not a not_(a)
単項プラス + a pos(a)
右シフト a >> b rshift(a, b)
スライス指定代入 seq[i:j] = values setitem(seq, slice(i, j), values)
スライス指定削除 del seq[i:j] delitem(seq, slice(i, j))
スライス参照 seq[i:j] getitem(seq, slice(i, j))
文字列フォーマッティング s % obj mod(s, obj)
減算 a - b sub(a, b)
真偽判定 obj truth(obj)
より小 a < b lt(a, b)
より小または一致 a <= b le(a, b)
一致 a == b eq(a, b)
不一致 a != b ne(a, b)
より大または一致 a >= b ge(a, b)
より大 a > b gt(a, b)

初歩的な内容

[編集]

関数

[編集]

関数は、プログラミングにおいて再利用可能なコードのブロックです。特定のタスクや処理を実行するために設計されています。関数は、特定の入力(引数)を受け取り、それを処理し、結果を出力(戻り値)として返すことができます。

関数の主な利点は次の通りです:

  1. 再利用性: 同じ処理を繰り返し記述する必要がなく、関数を呼び出すことで同じ処理を実行できます。
  2. モジュール化: コードをより小さな部分に分割し、管理しやすくします。
  3. 保守性: コードを関数単位で修正したり変更したりすることが容易になります。
  4. 可読性: 適切に名前付けされた関数は、コードを理解しやすくします。

プログラミング言語によって関数の使い方や書き方は異なりますが、基本的な構造は似ています。関数は通常、次のような形式で定義されます:

def function_name(parameters):
    # 処理
    # ...
    return result

例えば、Pythonでの関数定義はこのようになります。

def add_numbers(a, b):
    sum = a + b
    return sum

この例では、add_numbersという関数が定義されており、abという2つの引数を受け取ります。これらの引数を使ってsumを計算し、その結果をreturn文で返します。

関数はその他にも多くの機能を持ち、異なる言語においても様々な特性を持っています。

引数のある関数

[編集]
(コード例)
def func(a) :
    print("計算するよ")
    b = a * 2
    print(a,"を2倍したら",b)

a = 1
func(a)

a = 5
func(a)

a = 80
func(a)

(実行結果↓)

計算するよ
1 を2倍したら 2
計算するよ
5 を2倍したら 10
計算するよ
80 を2倍したら 160

ある処理を繰返し行いたい場合、関数をつかうことで、記述をへらせます。 関数に作業させる際、関数外で定義された値を、上記のように利用する事ができ、そのような変数を「引数」(ひきすう)といいます。

上記のコードのうち、関数の定義部分は、

def func(a) :
    print("計算するよ")
    b = a * 2
    print(a,"を2倍したら",b)

↑ この範囲が、関数の定義部分です。


引数のある関数の定義の書式は、

def 関数名(引数) :
    処理内容

というふうになります。

「引数」は「ひきすう」と読みます。


引数が2個以上の場合

[編集]
def menseki(a,b) :
    print("面積を計算するよ")
    print(a * b)

a = 3
b = 5

menseki(a,b)


結果
面積を計算するよ
15


下記のように、呼び出し時に引数の値を「menseki(3,5)」のように指定することもできます。

def menseki(a,b) :
    print("面積を計算するよ")
    print(a * b)

menseki(3,5)


結果
面積を計算するよ
15


やや難しい内容

[編集]

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

[編集]
"""
グローバル変数とローカル変数の例
"""
a = 1
b = 2
c = 3

def f2():
    """
    f2で参照されるa,b,cはグローバル変数
    """
    print(f"f2:{a=},{b=},{c=},")

def func(a) :
    """
    funcで参照されるaは仮引数
    funcで参照されるbはローカル変数
    funcで参照されるcはグローバル変数
    """
    b = a * 2
    print(f"func:{a=},{b=},{c=},")
    f2()

func(111)
print(f"GLOBAL:{a=},{b=},{c=},")
実行結果
func:a=111,b=222,c=3,
f2:a=1,b=2,c=3,
GLOBAL:a=1,b=2,c=3,
f2
関数から呼び出された関数で、仮引数にもローカル変数にも見つからなかった変数は、グローバル変数から探される。
func
仮引数とグローバル変数の名前が同じ場合、仮引数が参照される。
グローバル変数は仮引数にシャドーイングされる。
ローカル変数とグローバル変数の名前が同じ場合、ローカル変数が参照される。
グローバル変数はローカル変数にシャドーイングされる。
ローカル変数の有効範囲(スコープ)は、関数の終わりまでです。

このようにpythonでは、関数内で数を置きかえる動作は、原則として、関数外の動作に影響を与えません。

組込み関数id

[編集]

組込み関数idを使うとオブジェクトのidを得ることができます。 2つの変数同士のidが同じ場合、2つの変数は同じオブジェクトにバインドされています。 大概の型のオブジェクトのidはメモリー上のアドレスですが、整数のようにそうではない型も少数ながらあります。

idの例
"""
idの例
"""
a = 1
b = 2
c = 3

def f2():
    """
    f2で参照されるa,b,cはグローバル変数
    """
    print(f"f2:{a=}({id(a)=}),{b=}({id(b)=}),{c=}({id(c)=}),")

def func(a) :
    """
    funcで参照されるaは仮引数
    funcで参照されるbはローカル変数
    funcで参照されるcはグローバル変数
    """
    b = a * 2
    print(f"func:{a=}({id(a)=}),{b=}({id(b)=}),{c=}({id(c)=}),")
    f2()

func(111)
print(f"GLOBAL:{a=}({id(a)=}),{b=}({id(b)=}),{c=}({id(c)=}),")
実行結果
func:a=111(id(a)=9792128),b=222(id(b)=9795680),c=3(id(c)=9788672),
f2:a=1(id(a)=9788608),b=2(id(b)=9788640),c=3(id(c)=9788672),
GLOBAL:a=1(id(a)=9788608),b=2(id(b)=9788640),c=3(id(c)=9788672),

戻り値

[編集]

関数の戻り値(return value;返り値・返却値とも)は、return 文で返します。

関数の戻り値
import inspect

def f(a) :
    """ 引数を戻り値とする関数 """
    return a

print(inspect.getsource(f))
print(f'''\
{f(1)=}
{f(3.1415926536)=}
{f("string")=}
''')

def n(a) :
    """ return文のない関数 """
    pass

print(inspect.getsource(n))
print(f'''\
{n(n)=}
{n(3.1415926536)=}
{n("string")=}
''')

def x(a) :
    """ return文に引数のない関数 """
    return

print(inspect.getsource(x))
print(f'''\
{x(n)=}
{x(3.1415926536)=}
{x("string")=}
''')
関数は多くのケースで何らかの値を返します。
これを戻り値とよびます。
関数は、return文の引数を戻り値とします。
return文に出会わず関数定義の終わりに達した場合は、オブジェクトNoneが返ります。
return文で戻り値を指定しない場合は、オブジェクトNoneが返ります。
def f(a, b) :
    return a + b
この関数は引数 a と b を受けとり、足した結果を返します。
return文による途中終了
[編集]

return文があると、その行で関数が終了します。

def work() :
    print("a")
    return 0
    print("b")

work()
work()
実行結果
a
a
print("b") が実行されることはありません。

キーワード引数

[編集]

関数の仮引数には名前(識別子)がありますが、仮引数を明示して関数の実引数を渡し呼出すことができます。 このような識別子を明示して呼びされた実引数をキーワード引数と言います。

キーワード引数
def sub(left, right) :
    return left - right

print(f"{sub(3, 4)=}")
print(f"{sub(right=8, left=19)=}")
実行結果
sub(3, 4)=-1 
sub(right=8, left=19)=11
同じ関数を、キーワード引数で呼出すことも、従前の引数形式で呼出すこともできます。
キーワード引数では引数の順序は問わず、仮引数の識別子で参照されます。
上記の例では第一引数と第二引数の順序が入れ替わっています。
#可変長引数関数を使うことで、キーワード引数で呼出されたのか、従前の引数形式で呼出されたかを判別できます。

ディフォルト引数

[編集]

関数の引数には、既定値(ディフォルト)を設けることができます。

def add(a=0, b=0, c=0) :
    return a+b+c

print(f"""\
{add()=}
{add(1)=}
{add(2,3)=}
{add(4,5,6)=}
""")
実行結果
add()=0
add(1)=1
add(2,3)=5 
add(4,5,6)=15

可変長引数関数

[編集]

関数の引数は可変長にできます。

def add(*args, **kwargs) :
    result = 0
    for i in args :
        result += i
    for _, i in kwargs.items() :
        result += i
    return result

print(f"""\
{add()=}
{add(1)=}
{add(2,3)=}
{add(4,5,6)=}
{add(1,2,3,4,5,6,7,8,9,10)=}
{add(a=1)=}
{add(a=2,x=3)=}
{add(q=4,p=5,z=6)=}
""")
実行結果
add()=0
add(1)=1
add(2,3)=5
add(4,5,6)=15
add(1,2,3,4,5,6,7,8,9,10)=55
add(a=1)=1
add(a=2,x=3)=5
add(q=4,p=5,z=6)=15
この様に、キーワード引数を可変長引数に含めることもできます。

残余引数

[編集]

関数の定義で固定された引数とともに、可変長引数を持つことができます。 ここで、残余引数は、可変長引数の後ろに定義される一連の引数です。 残余引数のために、アスタリスク(*)を使用します。

def my_func(a, b, *args):
    print(a)
    print(b)
    for arg in args:
        print(arg)

これで、my_func()関数は少なくともaとbの2つの引数を取り、残りの引数を可変長引数として扱います。

多値返却風な処理

[編集]

Pythonには、厳密な意味での多値返却はありませんが、タプルやリストを返すことで多値返しに近いことができます。

多値返し風な処理
def addsub(x, y) :
    a, b = x + y, x - y
    return a, b

def mulquoremdiv(x, y) :
    return x * y, x // y, x % y, x / y

a, s = addsub(13, 5)
m, q, r, d = mulquoremdiv(19, 7)
print(f'''\
{a=}, {s=} 
{m=}, {q=}, {r=}, {d=}
''')
実行結果
a=18, s=8 
m=133, q=2, r=5, d=2.7142857142857144

「多値返却風な処理」や「多値返しに近いこと」と歯切れが悪いのは、型アノテーション

def addsub(x: int, y: int) -> int, int: # Error!
    a, b = x + y, x - y
    return a, b


def mulquoremdiv(x: int, y: int) -> int, int, int, float: # Error!
    return x * y, x // y, x % y, x / y

としたいのですが、

from typing import Tuple

def addsub(x: int, y: int) -> Tuple[int, int]:
    a, b = x + y, x - y
    return a, b

def mulquoremdiv(x: int, y: int) -> Tuple[int, int, int, float] :
    return x * y, x // y, x % y, x / y

としなければならず、タプルを返していることを明確に意識する必要があるからです。

デコレーター

[編集]

デコレーター(decorator)は、関数の内容を書き換えずに修飾するための仕組みです。 関数の引数に関数を指定します。既存の関数の前に@{デコレーター名}を付けることで、その関数を修飾することができます。

形式
def デコレーター名(デコレーターの引数) : 
    def ラッパー関数名(*args, **kwargs) :
        # 前処理
        result = デコレーターの引数(*args, **kwargs)
        # 後処理
        return result
    return ラッパー関数名

@デコレーター名
def 修飾される側の関数(その引数) :
    修飾される側の関数の処理
コード例
def my_decorator(fn) :
    def _wrapper(*args, **kwargs) :
        print(f"my_decorator<prologue>:{fn.__name__=}:{args=}, {kwargs=}")
        result = fn(*args, **kwargs)
        print(f"my_decorator<epilogue>:{result=}")
        return result
    return _wrapper

@my_decorator
def calc(left, right) :
    return left + right

print(f'''\
{calc(3, 5)=}
{calc(right=8, left=9)=}''')
実行結果
my_decorator<prologue>:fn.__name__='calc':args=(3, 5), kwargs={}
my_decorator<epilogue>:result=8
my_decorator<prologue>:fn.__name__='calc':args=(), kwargs={'right': 8, 'left': 9}
my_decorator<epilogue>:result=17
calc(3, 5)=8
calc(right=8, left=9)=17

デコレターの文法は、以下のような糖衣構文です。

@my_decorator
def fn(...):
    ...

# は

def fn(...):
    ...
fn = my_decorator(fn)

#と同じ
デコレーター・パターン

デコレーター・パターンは、オブジェクト指向プログラミングにおいて、同じクラスの他のオブジェクトの動作に影響を与えることなく、個々のオブジェクトに動的に動作を追加することができるデザインパターンです。 デコレーター・パターンは、単一責任原則(Single Responsibility Principle)を遵守するために有用で、独自の関心領域を持つクラス間で機能を分割することができます。 デコレーターの使用は、全く新しいオブジェクトを定義することなく、オブジェクトの動作を拡張することができるため、サブクラス化よりも効率的です。

Pythonのデコレーター構文は、デコレーター・パターンの言語支援と言えます。

global 文

[編集]

ローカル変数や仮引数にグローバル変数がシャドーイングされた場合、 関数の中でも、

global 変数

と変数宣言することにより、その変数をグローバル変数として取り扱えます。

コード例
a = 10
b = 11

def func(a) :
    global b
    print(f"func:{a=},{b=}")
    b = a * 2
    print(f"func:{a=},{b=}")

func(a)
print(f"GLOBAL:{a=},{b=}")
表示結果
func:a=10,b=11
func:a=10,b=20
GLOBAL:a=10,b=20

C言語には、このような機能(関数内で変数をグローバル宣言する機能)は、ありません。 C++では、グローバル変数の参照に :: を前置することでシャドーイングを回避できます。


関数内で新たなグローバル変数を作る

[編集]
コード例
a = 10

def func(a) :
    global b
    # print(f"func:{a=},{b=}") ← この時点では b は未定義
    b = a * 2
    print(f"func:{a=},{b=}")

func(a)
print(f"GLOBAL:{a=},{b=}")
表示結果
func:a=10,b=20
GLOBAL:a=10,b=20

nonlocal文

[編集]

nonlocal文は、内包関数から、自分を呼び出した関数のローカル変数にアクセスする仕組みです。 global文と違い、新たな変数を作ることはできません。

コード例
def outer() :
    f = 25
    def inner() :    # 関数内関数
        nonlocal f
        f = 13
        return 1
           
    inner()
    print(f)
    
outer()
実行結果
13
nonlocal の行をコメントにすると、結果は 「25」 に変わります。

クロージャ

[編集]

クロージャ(関数クロージャ)は、外側の変数を格納する関数です。

コード例
def f(z) :
    def _f() :
        nonlocal z
        z += 1
        return z
    return _f
    
q = f(-2)
print(q())
print(q())
print(q())
print(q())
実行結果
-1
0
1
2
_fをクロージャ、fをエンクロージャといいます。

この絵柄に見覚えがある人もいると思います。デコレーターの引数(デコレート対象の関数)はラッパー関数は格納した変数です。

シーケンス

[編集]

Pythonでは、複数のオブジェクトを要素として持つオブジェクト(=コレクション)のうち、整数のインデックスによって要素を参照できるオブジェクトのグループをシーケンス(sequence)と呼びます[1]。 組込み型の代表的なシーケンスは、リストタプルレンジ オブジェクトです[2]

スライス記法

[編集]

シーケンスに共通の機能として、スライス記法があります。

スライス記法
for li in (
    [i for i in range(10)],
    (0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
    range(10),
    "0123456789",
    b"0123456789",
):
    print(
        f"""\
{type(li)=}
{li=}
{li[2:]=}
{li[2:6]=}
{li[:6]=}
{li[:]=}
{id(li)=},{id(li[:])=}
{id(li)=},{id(li[:9])=}
{li[1:8:2]=}
{li[1::2]=}
"""
    )
実行結果
type(li)=<class 'list'>
li=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
li[2:]=[2, 3, 4, 5, 6, 7, 8, 9]
li[2:6]=[2, 3, 4, 5]
li[:6]=[0, 1, 2, 3, 4, 5]
li[:]=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
id(li)=23247490610496,id(li[:])=23247489732224
id(li)=23247490610496,id(li[:9])=23247489732224
li[1:8:2]=[1, 3, 5, 7]
li[1::2]=[1, 3, 5, 7, 9]

type(li)=<class 'tuple'>
li=(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
li[2:]=(2, 3, 4, 5, 6, 7, 8, 9)
li[2:6]=(2, 3, 4, 5)
li[:6]=(0, 1, 2, 3, 4, 5)
li[:]=(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
id(li)=23247491653056,id(li[:])=23247491653056
id(li)=23247491653056,id(li[:9])=23247490368448
li[1:8:2]=(1, 3, 5, 7)
li[1::2]=(1, 3, 5, 7, 9)

type(li)=<class 'range'>
li=range(0, 10)
li[2:]=range(2, 10)
li[2:6]=range(2, 6)
li[:6]=range(0, 6)
li[:]=range(0, 10)
id(li)=23247491019616,id(li[:])=23247490390464
id(li)=23247491019616,id(li[:9])=23247490390464
li[1:8:2]=range(1, 8, 2)
li[1::2]=range(1, 10, 2)

type(li)=<class 'str'>
li='0123456789'
li[2:]='23456789'
li[2:6]='2345'
li[:6]='012345'
li[:]='0123456789'
id(li)=23247489812400,id(li[:])=23247489812400
id(li)=23247489812400,id(li[:9])=23247489814704
li[1:8:2]='1357'
li[1::2]='13579'

type(li)=<class 'bytes'>
li=b'0123456789'
li[2:]=b'23456789'
li[2:6]=b'2345'
li[:6]=b'012345'
li[:]=b'0123456789'
id(li)=23247491020288,id(li[:])=23247491020288
id(li)=23247491020288,id(li[:9])=23247490390224
li[1:8:2]=b'1357'
li[1::2]=b'13579'

シーケンス・オブジェクトごとのアトリビュートの有無

[編集]

組込み関数hasattr(obj, name)を使うと、オブジェクトobjが名前nameな属性を持っているかの検査ができます。

シーケンス・オブジェクトごとのアトリビュートの有無
sequences = (
    [i for i in range(10)],
    (0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
    range(10),
    "0123456789",
    b"0123456789",
    zip([],[]),
)
attrs = set()

for li in sequences:
    for x in dir(li):
        attrs.add(x)

c = 0
for x in sorted(attrs):
    if c % 10 == 0:
        print("Type", ", ".join(str(type(li)) for li in sequences), sep=": ")
    print(x, ", ".join("o" if hasattr(li, x) else "x" for li in sequences), sep=": ")
    c += 1
else:
    print("Type", ", ".join(str(type(li)) for li in sequences), sep=": ")
実行結果
Type: <class 'list'>, <class 'tuple'>, <class 'range'>, <class 'str'>, <class 'bytes'>, <class 'zip'>
__add__: o, o, x, o, o, x
__bool__: x, x, o, x, x, x
__class__: o, o, o, o, o, o
__contains__: o, o, o, o, o, x
__delattr__: o, o, o, o, o, o
__delitem__: o, x, x, x, x, x
__dir__: o, o, o, o, o, o
__doc__: o, o, o, o, o, o
__eq__: o, o, o, o, o, o
__format__: o, o, o, o, o, o
Type: <class 'list'>, <class 'tuple'>, <class 'range'>, <class 'str'>, <class 'bytes'>, <class 'zip'>
__ge__: o, o, o, o, o, o
__getattribute__: o, o, o, o, o, o
__getitem__: o, o, o, o, o, x
__getnewargs__: x, o, x, o, o, x
__gt__: o, o, o, o, o, o
__hash__: o, o, o, o, o, o
__iadd__: o, x, x, x, x, x
__imul__: o, x, x, x, x, x
__init__: o, o, o, o, o, o
__init_subclass__: o, o, o, o, o, o
Type: <class 'list'>, <class 'tuple'>, <class 'range'>, <class 'str'>, <class 'bytes'>, <class 'zip'>
__iter__: o, o, o, o, o, o
__le__: o, o, o, o, o, o
__len__: o, o, o, o, o, x
__lt__: o, o, o, o, o, o
__mod__: x, x, x, o, o, x
__mul__: o, o, x, o, o, x
__ne__: o, o, o, o, o, o
__new__: o, o, o, o, o, o
__next__: x, x, x, x, x, o
__reduce__: o, o, o, o, o, o
Type: <class 'list'>, <class 'tuple'>, <class 'range'>, <class 'str'>, <class 'bytes'>, <class 'zip'>
__reduce_ex__: o, o, o, o, o, o
__repr__: o, o, o, o, o, o
__reversed__: o, x, o, x, x, x
__rmod__: x, x, x, o, o, x
__rmul__: o, o, x, o, o, x
__setattr__: o, o, o, o, o, o
__setitem__: o, x, x, x, x, x
__sizeof__: o, o, o, o, o, o
__str__: o, o, o, o, o, o
__subclasshook__: o, o, o, o, o, o
Type: <class 'list'>, <class 'tuple'>, <class 'range'>, <class 'str'>, <class 'bytes'>, <class 'zip'>
append: o, x, x, x, x, x
capitalize: x, x, x, o, o, x
casefold: x, x, x, o, x, x
center: x, x, x, o, o, x
clear: o, x, x, x, x, x
copy: o, x, x, x, x, x
count: o, o, o, o, o, x
decode: x, x, x, x, o, x
encode: x, x, x, o, x, x
endswith: x, x, x, o, o, x
Type: <class 'list'>, <class 'tuple'>, <class 'range'>, <class 'str'>, <class 'bytes'>, <class 'zip'>
expandtabs: x, x, x, o, o, x
extend: o, x, x, x, x, x
find: x, x, x, o, o, x
format: x, x, x, o, x, x
format_map: x, x, x, o, x, x
fromhex: x, x, x, x, o, x
hex: x, x, x, x, o, x
index: o, o, o, o, o, x
insert: o, x, x, x, x, x
isalnum: x, x, x, o, o, x
Type: <class 'list'>, <class 'tuple'>, <class 'range'>, <class 'str'>, <class 'bytes'>, <class 'zip'>
isalpha: x, x, x, o, o, x
isascii: x, x, x, o, o, x
isdecimal: x, x, x, o, x, x
isdigit: x, x, x, o, o, x
isidentifier: x, x, x, o, x, x
islower: x, x, x, o, o, x
isnumeric: x, x, x, o, x, x
isprintable: x, x, x, o, x, x
isspace: x, x, x, o, o, x
istitle: x, x, x, o, o, x
Type: <class 'list'>, <class 'tuple'>, <class 'range'>, <class 'str'>, <class 'bytes'>, <class 'zip'>
isupper: x, x, x, o, o, x
join: x, x, x, o, o, x
ljust: x, x, x, o, o, x
lower: x, x, x, o, o, x
lstrip: x, x, x, o, o, x
maketrans: x, x, x, o, o, x
partition: x, x, x, o, o, x
pop: o, x, x, x, x, x
remove: o, x, x, x, x, x
replace: x, x, x, o, o, x
Type: <class 'list'>, <class 'tuple'>, <class 'range'>, <class 'str'>, <class 'bytes'>, <class 'zip'>
reverse: o, x, x, x, x, x
rfind: x, x, x, o, o, x
rindex: x, x, x, o, o, x
rjust: x, x, x, o, o, x
rpartition: x, x, x, o, o, x
rsplit: x, x, x, o, o, x
rstrip: x, x, x, o, o, x
sort: o, x, x, x, x, x
split: x, x, x, o, o, x
splitlines: x, x, x, o, o, x
Type: <class 'list'>, <class 'tuple'>, <class 'range'>, <class 'str'>, <class 'bytes'>, <class 'zip'>
start: x, x, o, x, x, x
startswith: x, x, x, o, o, x
step: x, x, o, x, x, x
stop: x, x, o, x, x, x
strip: x, x, x, o, o, x
swapcase: x, x, x, o, o, x
title: x, x, x, o, o, x
translate: x, x, x, o, o, x
upper: x, x, x, o, o, x
zfill: x, x, x, o, o, x
Type: <class 'list'>, <class 'tuple'>, <class 'range'>, <class 'str'>, <class 'bytes'>, <class 'zip'>

脚註

[編集]
  1. ^ sequenceと言う型があるわけではありません。
  2. ^ 辞書も3.6以降では順序固定ですが、シーケンスの一種だと考えることは稀です。

Pythonにおけるリスト(List)は、複数の要素を格納できるデータ構造で、順序があります。以下は、Pythonのリストを操作する基本的な操作です。

コード例
# リストの作成
my_list = [1, 2, 3, 4, 5]

# 要素のアクセス
print(my_list[0])  # 1を出力
print(my_list[-1])  # 最後の要素を出力

# スライス
subset = my_list[1:4]  # インデックス1から3(4未満)までの要素を取得

# 要素の追加
my_list.append(6)  # リストの末尾に要素を追加

# 要素の挿入
my_list.insert(2, 7)  # インデックス2の位置に要素7を挿入

# 要素の削除
my_list.remove(3)  # 値が3の要素を削除

# インデックスを指定して削除
del my_list[2]  # インデックス2の要素を削除

# リストの結合
new_list = my_list + [8, 9, 10]

# リストの長さ
length = len(my_list)

# リストのループ
for element in my_list:
    print(element)

# リスト内包表記
squared_numbers = [x**2 for x in my_list]

これらはリストを使った基本的な操作です。リストは非常に柔軟で強力なデータ構造であり、さまざまな操作や機能が利用可能です。

Pythonのリストには、さまざまな演算子があります。以下に、リストでよく使用される主な演算子をいくつか示します。

コード例
# 結合演算子 (+): 2つのリストを結合して新しいリストを作成します。
list1 = [1, 2, 3]
list2 = [4, 5, 6]
result = list1 + list2
# resultは[1, 2, 3, 4, 5, 6]

# 繰り返し演算子 (*): リストを指定した回数繰り返します。
list1 = [1, 2, 3]
result = list1 * 3
# resultは[1, 2, 3, 1, 2, 3, 1, 2, 3]

# 比較演算子: リスト同士を比較するために、等号 (==) や不等号 (!=) を使用できます。
list1 = [1, 2, 3]
list2 = [1, 2, 3]
list3 = [4, 5, 6]

print(list1 == list2)  # True
print(list1 != list3)  # True

# メンバーシップ演算子 (in, not in): 特定の要素がリストに含まれているかどうかを確認します。
list1 = [1, 2, 3]

print(2 in list1)    # True
print(4 not in list1)  # True
  1. 結合演算子 (+): 2つのリストを結合して新しいリストを作成します。
  2. 繰り返し演算子 (*): リストを指定した回数繰り返します。
  3. 比較演算子: リスト同士を比較するために、等号 (==) や不等号 (!=) を使用できます。
  4. メンバーシップ演算子 (in, not in): 特定の要素がリストに含まれているかどうかを確認します。

これらの演算子を使って、リストを操作し、組み合わせることができます。

リストの仕様

[編集]

リスト( list )は、任意のオブジェクトをゼロ個以上、順次付けて保持できるコレクションです[1]

リストリテラル

[編集]
リストリテラル
print(f"""\
{[]=}
{list()=}
{list((1,2,3))=}
{list(i for i in range(5))=}
{[10,"ABC"]=}
{[[1,"one"], [2,"two"],[3,"three"]]=}
{[
    [1,"壱"],
    [2,"弐"],
    [3,"参"]
    ]=}
""")
実行結果
[]=[]
list()=[]
list((1,2,3))=[1, 2, 3]
list(i for i in range(5))=[0, 1, 2, 3, 4]
[10,"ABC"]=[10, 'ABC']
[[1,"one"], [2,"two"],[3,"three"]]=[[1, 'one'], [2, 'two'], [3, 'three']]
[
    [1,"壱"],
    [2,"弐"],
    [3,"参"]
    ]=[[1, '壱'], [2, '弐'], [3, '参']]

リストは、要素を ,(カンマ) で区切り全体を [ ] で囲みます。 要素の型は同じである必要はありません。

リストと演算子

[編集]
リストと演算子
li = [10 ,"ABC" ,30]
print(f'''\
{li=}
{li[1]=}
{li[-1]=}
{li + [2,3,4]=}
{li * 2=}
{2 * li=}
{li == [10 ,"ABC" ,30]=}
{li != [10 ,"ABC" ,30]=}
{li < [10 ,"ABC" ,30]=}
{li > [10 ,"ABC" ,30]=}
''')
実行結果
li=[10, 'ABC', 30]
li[1]='ABC'
li[-1]=30
li + [2,3,4]=[10, 'ABC', 30, 2, 3, 4]
li * 2=[10, 'ABC', 30, 10, 'ABC', 30]
2 * li=[10, 'ABC', 30, 10, 'ABC', 30]
li == [10 ,"ABC" ,30]=True
li != [10 ,"ABC" ,30]=False
li < [10 ,"ABC" ,30]=False
li > [10 ,"ABC" ,30]=False
リストの要素は、インデックス演算子で参照できます。
リスト内の要素の順位はタプルやレンジと同じく、0番から始まります。
負のインデクスiは、len(self)+iを表します。
リスト同士の足し算は、連結した新しいリストを返します。
リストtと整数nとの乗算は、tをn回繰り返したリストを返します。
整数nとリストtとの乗算は、tをn回繰り返したリストを返します。
リスト同士は、比較や大小判別ができます。

リストはミュータブル

[編集]

リストの各要素を、代入・置き換えすることもできます。

myList = [10 ,"ABC" ,30]
myList[0] = 4
print (myList)
実行結果
[4, 'ABC', 30]
です。「10」が「4」に置き換わっています。

多次元リスト

[編集]

リストの中にリストを入れることも出来ます。ただし、下記のように入れたリストの項目数が等しくなるようにする必要があります。

リストの中にリストを入れたものを2次元リスト(または2重リスト)といい、

リストの中にリストを入れたもののなかに、さらにリストを入れたものを3次元リストと言います。

二次元リストのコード例
carList = [ ["山田" , "red" , 1234 ] , ["伊藤" , "blue" , 555 ]    ]

print(carList[0][0] )
print(carList[0][1] )
print(carList[1][0] )
実行結果
山田
red
伊藤

map関数

[編集]

組込み関数mapを使うと、iterableオブジェクトの全ての要素に、一括で何かの関数を適用する事ができます。

関数宣言
map(function, iterable)
コード例
myList = [-7 , -2, 5]

print(f'''\
{myList=}
{map(abs, myList)=}
{list(map(abs, myList))=}
{list(abs(x) for x in myList)=}
{[abs(x) for x in myList]=}
{[-x if x < 0 else x for x in myList]=}
''')
実行結果
myList=[-7, -2, 5]
map(abs, myList)=<map object at 0x149ab6e4c0d0>
list(map(abs, myList))=[7, 2, 5]
list(abs(x) for x in myList)=[7, 2, 5]
[abs(x) for x in myList]=[7, 2, 5]
[-x if x < 0 else x for x in myList]=[7, 2, 5]
リスト myList の要素の絶対値を得るプログラムです。
map関数の第一引数は関数が要求されますが、1つの引数を取り値を帰っす必要があります。ここでは組込み関数absを使いました。
map関数はリスト...ではなく map object を返します。
map objectはリストコンストラクタであるlist関数でリスト化できます。
map関数はジェネレーター式(function(x) for x in iterable)と等価です。
またリスト化するなら、リスト内包表記[function(x) for x in iterable]と等価です。
内包表記であれば、absの呼出しは条件演算子-x if x < 0 else xで置換える事ができます。

abs のような組込み関数だけでなく、ユーザー定義関数やlambdaもmap関数の第一引数にすることができます。

filter関数

[編集]

組込み関数filterは、iterableオブジェクトの要素の中から、条件に適合するものだけを選び出して、新たなリストを作ります、

関数宣言
filter(function, iterable)
引数
function
残すかの条件関数False以外を返すと残す
iterable
対処とするiterableオブジェクト
コード例
myList = [5, 2, 8, 3, 6, 1]

print(f'''\
{myList=}
{filter(lambda x:x >= 3, myList)=}
{list(filter(lambda x:x >= 3, myList))=}
{list(x for x in myList if x >= 3)=}
{[x for x in myList if x >= 3]=}
''')
実行結果
myList=[5, 2, 8, 3, 6, 1]
filter(lambda x:x >= 3, myList)=<filter object at 0x154a32dccd00>
list(filter(lambda x:x >= 3, myList))=[5, 8, 3, 6]
list(x for x in myList if x >= 3)=[5, 8, 3, 6] 
[x for x in myList if x >= 3]=[5, 8, 3, 6]
リスト myList から3より多い要素を残すプログラムです。
filter関数の第一引数は関数を要求されますが、名前は不要で繰返し使う予定もないので lambda を使いました。
filter関数はリスト...ではなく filter object を返します。
filter objectはリストコンストラクタであるlist関数でリスト化できます。
filter関数はジェネレーター式(x for x in iterable if function(x))と等価です。
またリスト化するなら、リスト内包表記[x for x in iterable if function(x)]と等価です。

filter関数の第一引数をNoneとした場合

[編集]
コード例
myList = [5, set(), 8, "", 3, False, 6, None, 1, tuple(), 0, 3, []]

print(f'''\
{myList=}
{filter(None, myList)=}
{list(filter(None, myList))=}
{list(x for x in myList if x)=}
{[x for x in myList if x]=}
''')
実行結果
myList=[5, set(), 8, '', 3, False, 6, None, 1, (), 3, []]
filter(None, myList)=<filter object at 0x1514a15ee0d0>
list(filter(None, myList))=[5, 8, 3, 6, 1, 3]
list(x for x in myList if x)=[5, 8, 3, 6, 1, 3]
[x for x in myList if x]=[5, 8, 3, 6, 1, 3]
リスト myList からfalsy[2]でない要素を残すプログラムです。
filter関数の第一引数は関数を要求されますが、Noneを渡すとfalsyな要素を除去します。
この場合も、filter関数はリスト...ではなく filter object を返します。
この場合も、filter objectはリストコンストラクタであるlist関数でリスト化できます。
この場合は、filter関数はジェネレーター式(x for x in iterable if x)と等価です。
この場合はリスト化するなら、リスト内包表記[x for x in iterable if x]と等価です。

リスト内包表記を使った例

[編集]

上記のmap関数とfilter関数の使用例はリスト内包表記をつかうと

コード例
myList = [-7 , -2, 5]
obj = [abs(i) for i in myList]
print(obj)

myList = [5, 2, 8, 6, 1]
obj = [i for i in myList if i >= 3]
print(obj)

と表現できます。 for式やif式、if-else式(条件演算子)はリスト内包表記と組合わせると関数呼出しを使わないでもイテレーションやケース分けができます。

絶対値を求める部分も、

obj = [-i if i < 0 else i for i in myList]

とインラインで表現できます。

リストのフィールド一覧

[編集]
リストのフィールド一覧
obj = []
for i in dir(obj):
    print(i, eval(f"type({obj}.{i})"))
実行結果
__add__ <class 'method-wrapper'>
__class__ <class 'type'>
__contains__ <class 'method-wrapper'>
__delattr__ <class 'method-wrapper'>
__delitem__ <class 'method-wrapper'>
__dir__ <class 'builtin_function_or_method'>
__doc__ <class 'str'>
__eq__ <class 'method-wrapper'>
__format__ <class 'builtin_function_or_method'>
__ge__ <class 'method-wrapper'>
__getattribute__ <class 'method-wrapper'>
__getitem__ <class 'builtin_function_or_method'>
__gt__ <class 'method-wrapper'>
__hash__ <class 'NoneType'>
__iadd__ <class 'method-wrapper'>
__imul__ <class 'method-wrapper'>
__init__ <class 'method-wrapper'>
__init_subclass__ <class 'builtin_function_or_method'>
__iter__ <class 'method-wrapper'>
__le__ <class 'method-wrapper'>
__len__ <class 'method-wrapper'>
__lt__ <class 'method-wrapper'>
__mul__ <class 'method-wrapper'>
__ne__ <class 'method-wrapper'>
__new__ <class 'builtin_function_or_method'>
__reduce__ <class 'builtin_function_or_method'>
__reduce_ex__ <class 'builtin_function_or_method'>
__repr__ <class 'method-wrapper'>
__reversed__ <class 'builtin_function_or_method'>
__rmul__ <class 'method-wrapper'>
__setattr__ <class 'method-wrapper'>
__setitem__ <class 'method-wrapper'>
__sizeof__ <class 'builtin_function_or_method'>
__str__ <class 'method-wrapper'>
__subclasshook__ <class 'builtin_function_or_method'>
append <class 'builtin_function_or_method'>
clear <class 'builtin_function_or_method'>
copy <class 'builtin_function_or_method'>
count <class 'builtin_function_or_method'>
extend <class 'builtin_function_or_method'>
index <class 'builtin_function_or_method'>
insert <class 'builtin_function_or_method'>
pop <class 'builtin_function_or_method'>
remove <class 'builtin_function_or_method'>
reverse <class 'builtin_function_or_method'> 
sort <class 'builtin_function_or_method'>

リストと演算子

[編集]
リストと演算子
print(f'''\
{[1,2,3] + [7,8,9] =}
{[1,2,3] * 2 =}
{2 in [1,2,3] =}
{[1,2,3] == [7,8,9] =}
{[1,2,3] == [1,2,3] =}
{[1,2,3] != [7,8,9] =}
{[1,2,3] != [1,2,3] =}
{[1,2,3] > [1,2] =}
{[1,2,3] < [1,2] =}
''')

import operator

print(f'''\
{operator.__add__([1,2,3], [7,8,9]) =}
{operator.__mul__([1,2,3], 2) =}
{operator.__contains__([1,2,3],2)=}
{operator.__eq__([1,2,3], [7,8,9]) =}
{operator.__eq__([1,2,3], [1,2,3]) =}
{operator.__ne__([1,2,3], [7,8,9]) =}
{operator.__ne__([1,2,3], [1,2,3]) =}
{operator.__gt__([1,2,3], [1,2]) =}
{operator.__lt__([1,2,3], [1,2]) =}
''')

print(", ".join(vars(operator)))
実行結果
[1,2,3] + [7,8,9] =[1, 2, 3, 7, 8, 9]
[1,2,3] * 2 =[1, 2, 3, 1, 2, 3]
2 in [1,2,3] =True
[1,2,3] == [7,8,9] =False
[1,2,3] == [1,2,3] =True
[1,2,3] != [7,8,9] =True
[1,2,3] != [1,2,3] =False
[1,2,3] > [1,2] =True
[1,2,3] < [1,2] =False

operator.__add__([1,2,3], [7,8,9]) =[1, 2, 3, 7, 8, 9]
operator.__mul__([1,2,3], 2) =[1, 2, 3, 1, 2, 3]
operator.__contains__([1,2,3],2)=True
operator.__eq__([1,2,3], [7,8,9]) =False
operator.__eq__([1,2,3], [1,2,3]) =True
operator.__ne__([1,2,3], [7,8,9]) =True
operator.__ne__([1,2,3], [1,2,3]) =False
operator.__gt__([1,2,3], [1,2]) =True
operator.__lt__([1,2,3], [1,2]) =False

__name__, __doc__, __package__, __loader__, __spec__, __file__, __cached__, __builtins__, __all__, _abs, lt, le, eq, ne, ge, gt, not_, truth, is_, is_not, abs, add, and_, floordiv, index, inv, invert, lshift, mod, mul, matmul, neg, or_, pos, pow, rshift, sub, truediv, xor, concat, contains, countOf, delitem, getitem, indexOf, setitem, length_hint, attrgetter, itemgetter, methodcaller, iadd, iand, iconcat, ifloordiv, ilshift, imod, imul, imatmul, ior, ipow, irshift, isub, itruediv, ixor, __lt__, __le__, __eq__, __ne__, __ge__, __gt__, __not__, __abs__, __add__, __and__, __floordiv__, __index__, __inv__, __invert__, __lshift__, __mod__, __mul__, __matmul__, __neg__, __or__, __pos__, __pow__, __rshift__, __sub__, __truediv__, __xor__, __concat__, __contains__, __delitem__, __getitem__, __setitem__, __iadd__, __iand__, __iconcat__, __ifloordiv__, __ilshift__, __imod__, __imul__, __imatmul__, __ior__, __ipow__, __irshift__, __isub__, __itruediv__, __ixor__
モジュールoperatorを使うと、演算子を関数形式で呼び出すことができます[3]

他のプログラミング言語との比較

[編集]

他のプログラミング言語とPythonの類似点と差異をリストを中心に比較します。

Python
compound = [ 10, 20, 30 ]
Ruby
compound = [ 10, 20, 30 ]
完全に一致
JavaScript
let compound = [ 10, 20, 30 ]
let があること以外同じ
JavaScript(TypedArray)
let compound = new Int32Array([10,20,30])
ECMAScript 2015(ES6)でTypedArray(型付き配列)が追加されました。
TypedArrayはJSの配列とは違い、単一要素型で連続したメモリーに割当てられます。
C言語
int compound[] = { 10, 20, 30 };
だいぶ違う
意味的にも、C言語の配列は全ての要素の型は同一で連続したメモリーに割り付けられます。
Go(配列)
compound := [...]int{ 10, 20, 30 }
C言語ともだいぶ違う
意味的には、C言語の配列と同じく全ての要素の型は同一で連続したメモリーに割り付けられます。
Go(スライス)
compound := []int{ 10, 20, 30 }
よく似た構文ですが [ ] の中に ... がないのはスライス
スライスの要素は離散的なアドレスに配置され、動的に長さ(要素数)の変更が可能です。

宣言と初期化の部分に注目し様々な差異がありましたが、要素の参照は、

Python
compound[1]

の構文で、この部分はどの言語でもほぼ同じですが、FortranBASICでは、

Fortran, BASIC
compound(1)

のように丸括弧になります。

それぞれの言語のリストに似た型

Pythonに「配列」というデータ型は存在しません[4]。C言語などに、配列というデータ型があります。

言語によっては、「配列」データ型と「リスト」データ型とが別個に存在するものもあります(たとえば Kotlin という言語には、配列(array)データ型と、リスト list データ型とが別々に存在します) なお、kotlin は現在では、Android スマートホンのアプリケーションプログラムの開発などで、よく使われる言語です。

また、Goには「リスト」はなく「スライス」slice があります(Goのスライスの機能はPythonやkotlinの「リスト」と一見似ていますが、Goのスライスは「要素の型が一致している必要がある」ので本質的に「リスト」とは違い、異種リストの実装には interface{} を使います)。

Goには、配列型と「スライス」slice の2つのデータ型がありよく混同されますが、スライスは要素のアクセスは線形時間 O(n)、配列の要素のアクセスは定数時間 O(1)であることが大きな違いです。

要素の参照速度による分類

[編集]

リストや配列に類似した型は、要素の参照にかかる時間によって

線形時間 O(n)が必要なもの
Pythonのリスト、Goのスライスはこれに当たります
個々の要素の型は異なっても良い
要素数の増減可能
定数時間 O(1)で済むもの
Pythonの標準モジュールの array や拡張モジュール NumPy、JavaScriptのTypedArray、C言語の配列、Goの配列
個々の要素の型は一致している必要がある
要素数は宣言時に確定する
宣言時の要素数に定数式しか受け付けない言語(過去のC言語やGo)と、宣言時の要素数に実行時まで確定しない式も受け付ける言語(現在のC言語など)がある

タプル

[編集]

タプル( tuple )は、任意のオブジェクトをゼロ個以上、順次付けて保持できるコレクションです[5]。 リストとよく似た特徴がありますが、リストと違い生成後は内容が変更できない「イミュータブル」なオブジェクトです。

タプルリテラル

[編集]
タプルリテラル
tpl0 = ()
tpl1 = (10,)
tpl2 = 10, "ABC", 30
tpl3 = (1,"one"), (2,"two"),(3,"three")
tpl4 = (
    (1,"壱"),
    (2,"弐"),
    (3,"参")
    )
print(tpl0)
print(tpl1)
print(tpl2)
print(tpl3)
print(tpl4)
実行結果
()
(10,)
(10, 'ABC', 30)
((1, 'one'), (2, 'two'), (3, 'three')) 
((1, '壱'), (2, '弐'), (3, '参'))
空のタプルは、空の括弧の組で作ることができます。
1つの項目からなるタプル(「シングルトン」(singleton))は、式にカンマを付けることで形成されます(式はそれ自体ではタプルを作らないので、括弧 ( ) は式のグループ化のために使用可能でなければならないからです)。
2つ以上の項目からなるタプルリテラルは、カンマで区切られた式のリストで形成されます。
タプルリテラルに限らず、式を括弧 ( ) で括ると複数行に渡って書くことができます。

タプルと演算子

[編集]
タプルと演算子
tpl = 10 ,"ABC" ,30
print(f'''\
{tpl=}
{tpl[1]=}
{tpl[-1]=}
{tpl + (2,3,4)=}
{tpl * 2=}
{2 * tpl=}
{tpl == (10 ,"ABC" ,30)=}
{tpl != (10 ,"ABC" ,30)=}
{tpl < (10 ,"ABC" ,30)=}
{tpl > (10 ,"ABC" ,30)=}
''')
実行結果
tpl=(10, 'ABC', 30)
tpl[1]='ABC'
tpl[-1]=30
tpl + (2,3,4)=(10, 'ABC', 30, 2, 3, 4)
tpl * 2=(10, 'ABC', 30, 10, 'ABC', 30)
2 * tpl=(10, 'ABC', 30, 10, 'ABC', 30)
tpl == (10 ,"ABC" ,30)=True
tpl != (10 ,"ABC" ,30)=False
tpl < (10 ,"ABC" ,30)=False
tpl > (10 ,"ABC" ,30)=False
タプルの要素は、インデックス演算子で参照できますが、左辺値は得られません(イミュータブルなので)。
タプル内の要素の順位はリストと同じく、0番から始まります。
負のインデクスiは、len(self)+iを表します。
タプル同士の足し算は、連結した新しいタプルを返します。
タプルtと整数nとの乗算は、tをn回繰り返したタプルを返します。
整数nとタプルtとの乗算は、tをn回繰り返したタプルを返します。
タプル同士は、比較や大小判別ができます。

タプルのフィールド一覧

[編集]
タプルのフィールド一覧
obj = tuple()
for i in dir(obj):
    print(i, eval(f"type({obj}.{i})"))
実行結果
__add__ <class 'method-wrapper'>
__class__ <class 'type'>
__contains__ <class 'method-wrapper'>
__delattr__ <class 'method-wrapper'>
__dir__ <class 'builtin_function_or_method'>
__doc__ <class 'str'>
__eq__ <class 'method-wrapper'>
__format__ <class 'builtin_function_or_method'>
__ge__ <class 'method-wrapper'>
__getattribute__ <class 'method-wrapper'>
__getitem__ <class 'method-wrapper'>
__getnewargs__ <class 'builtin_function_or_method'>
__gt__ <class 'method-wrapper'>
__hash__ <class 'method-wrapper'>
__init__ <class 'method-wrapper'>
__init_subclass__ <class 'builtin_function_or_method'>
__iter__ <class 'method-wrapper'>
__le__ <class 'method-wrapper'>
__len__ <class 'method-wrapper'>
__lt__ <class 'method-wrapper'>
__mul__ <class 'method-wrapper'>
__ne__ <class 'method-wrapper'>
__new__ <class 'builtin_function_or_method'>
__reduce__ <class 'builtin_function_or_method'>
__reduce_ex__ <class 'builtin_function_or_method'>
__repr__ <class 'method-wrapper'>
__rmul__ <class 'method-wrapper'>
__setattr__ <class 'method-wrapper'>
__sizeof__ <class 'builtin_function_or_method'>
__str__ <class 'method-wrapper'>
__subclasshook__ <class 'builtin_function_or_method'>
count <class 'builtin_function_or_method'>
index <class 'builtin_function_or_method'>

メソッドセットはリストに準じますが、イミュータブルなので append clear copy extend insert pop remove reverse sort の9つのメソッドはありません。

脚註

[編集]
  1. ^ 3.10.1 Documentation » The Python Language Reference » 3. Data model ¶3.2. The standard type hierarchy” (2021年12月16日). 2021年12月16日閲覧。
  2. ^ falsy: 組込み関数bool() に与えると False を返すような式。False, None の他、空集合(set())、空文字列()、0、空タプル(tuple())、空リスト([])など
  3. ^ operator — Standard operators as functions — Python 3.10.1 documentation” (2021年12月15日). 2021年12月15日閲覧。
  4. ^ 標準モジュールの array あるいは、拡張モジュールの NumPy で連続した領域に要素が配置される配列が提供されますが、組込みオブジェクトの配列はありません。
  5. ^ 3.10.1 Documentation » The Python Language Reference » 3. Data model ¶3.2. The standard type hierarchy” (2021年12月16日). 2021年12月16日閲覧。

レンジ

[編集]

レンジ( range )は、等差数列を表すシーケンスです[1]

コンストラクター

[編集]

レンジにリテラルはありません。 コンストラクターである組込み関数 range()を使って生成します。

コンストラクター
print(f"""\
{range(5)=}
{range(2,20)=}
{range(2,20,3)=}
{list(range(5))=}
{list(range(2,20))=}
{list(range(2,20,3))=}
""")
実行結果
range(5)=range(0, 5)
range(2,20)=range(2, 20)
range(2,20,3)=range(2, 20, 3)
list(range(5))=[0, 1, 2, 3, 4]
list(range(2,20))=[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
list(range(2,20,3))=[2, 5, 8, 11, 14, 17]
range関数の引数は変則的で、1つの場合はstart=0が仮定されます(str()・repr()・print()などで文字列化すると隠れた0が現れます)

レンジと演算子

[編集]
レンジと演算子
rng = range(2,50,3)
print(f'''\
{rng=} {list(rng)=}
{rng.start=} {rng.stop=} {rng.step=} 
{rng[1]=}
{rng[-1]=}
{rng[2:10:2]=} {list(rng[2:10:2])=}
{rng[2:10]=} {list(rng[2:10])=}
{rng[:10]=} {list(rng[:10])=}
{rng[2:]=} {list(rng[2:])=}
{rng == range(2,24,3)=}
{rng != range(2,24,3)=}
{7 in rng=}
''')
実行結果
rng=range(2, 50, 3) list(rng)=[2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47]
rng.start=2 rng.stop=50 rng.step=3 
rng[1]=5
rng[-1]=47
rng[2:10:2]=range(8, 32, 6) list(rng[2:10:2])=[8, 14, 20, 26]
rng[2:10]=range(8, 32, 3) list(rng[2:10])=[8, 11, 14, 17, 20, 23, 26, 29]
rng[:10]=range(2, 32, 3) list(rng[:10])=[2, 5, 8, 11, 14, 17, 20, 23, 26, 29]
rng[2:]=range(8, 50, 3) list(rng[2:])=[8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47]
rng == range(2,24,3)=False
rng != range(2,24,3)=True
7 in rng=False
レンジの要素は、インデックス演算子で参照できます。
レンジ内の要素の順位はタプルやレンジと同じく、0番から始まります。
負のインデクスiは、len(self)+iを表します。
レンジにスライス記法を適用すると、レンジが返ります。
レンジ同士は、比較ができます。
整数がレンジに含まれるかは、in演算子で検査できます。

for文との組み合わせ

[編集]

レンジは、for文の対象となるシーケンスとして使えます(これが一番一般的な使用例でしょう)。

コード例
for i in range(5):
    print(i)
実行結果
0
1
2
3
4

レンジのフィールド一覧

[編集]
レンジのフィールド一覧
obj = range(5)
for i in dir(obj):
    print(i, eval(f"type({obj}.{i})"))
実行結果
__bool__ <class 'method-wrapper'>
__class__ <class 'type'>
__contains__ <class 'method-wrapper'>
__delattr__ <class 'method-wrapper'>
__dir__ <class 'builtin_function_or_method'>
__doc__ <class 'str'>
__eq__ <class 'method-wrapper'>
__format__ <class 'builtin_function_or_method'>
__ge__ <class 'method-wrapper'>
__getattribute__ <class 'method-wrapper'>
__getitem__ <class 'method-wrapper'>
__gt__ <class 'method-wrapper'>
__hash__ <class 'method-wrapper'>
__init__ <class 'method-wrapper'>
__init_subclass__ <class 'builtin_function_or_method'>
__iter__ <class 'method-wrapper'>
__le__ <class 'method-wrapper'>
__len__ <class 'method-wrapper'>
__lt__ <class 'method-wrapper'>
__ne__ <class 'method-wrapper'>
__new__ <class 'builtin_function_or_method'>
__reduce__ <class 'builtin_function_or_method'>
__reduce_ex__ <class 'builtin_function_or_method'>
__repr__ <class 'method-wrapper'>
__reversed__ <class 'builtin_function_or_method'>
__setattr__ <class 'method-wrapper'>
__sizeof__ <class 'builtin_function_or_method'>
__str__ <class 'method-wrapper'>
__subclasshook__ <class 'builtin_function_or_method'>
count <class 'builtin_function_or_method'>
index <class 'builtin_function_or_method'>
start <class 'int'>
step <class 'int'>
stop <class 'int'>

脚註

[編集]
  1. ^ 3.10.1 Documentation » The Python Standard Library » Built-in Types” (2021年12月16日). 2021年12月16日閲覧。

Array

[編集]

Pythonの array モジュールは、効率的な数値計算のために配列を提供するものです。通常のリストよりもメモリ効率が高く、要素の型を指定できるのが特徴です[1]。 JavaScript の TypedArray や、C言語等の静的型付けの言語の配列に相当します。

通常、NumPyライブラリがより高度な数値計算のニーズに対応するために使用されます。

array モジュールを使用するには、まずモジュールをインポートします。以下は簡単な使用例です:

from array import array

# 'd' は倍精度浮動小数点型を示します
float_array = array('d', [1.0, 2.0, 3.0])

# 配列の要素へのアクセス
print(float_array[0])  # 出力: 1.0
print(float_array[1])  # 出力: 2.0
print(float_array[2])  # 出力: 3.0

ここで、'd'double(倍精度浮動小数点数)型を示しています。他にもいくつかの型が利用可能で、例えば 'i' は整数型を表します。

from array import array

# 'i' は符号付き整数型を示します
int_array = array('i', [1, 2, 3])

# 配列の要素へのアクセス
print(int_array[0])  # 出力: 1
print(int_array[1])  # 出力: 2
print(int_array[2])  # 出力: 3

array モジュールは通常、数値計算が必要な場合や大量のデータを扱う際に使用されます。ただし、リストよりも効率的である一方で柔軟性は少なく、同じ型の要素しか格納できません。

操作とイテレーション

[編集]

Pythonの array モジュールで生成されたオブジェクトは、通常のリストと似たように操作できますが、要素の型が制約されているため、一部の操作が異なります。以下に、array オブジェクトの生成、操作、イテレーションの例を示します。

from array import array

# 'd' は倍精度浮動小数点型を示します
float_array = array('d', [1.0, 2.0, 3.0])
print(f"{float_array=}") # => float_array=array('d', [1.0, 2.0, 3.0])
print(f"{type(float_array)=}") # => type(float_array)=<class 'array.array'>

# 要素へのアクセス
print(float_array[0])  # 出力: 1.0

# スライス
subset = float_array[1:3]  # 2番目から3番目までの要素を取得
print(f"{subset=}") # => subset=array('d', [2.0, 3.0])
print(f"{type(subset)=}") # => type(subset)=<class 'array.array'>

# 要素の変更
float_array[1] = 4.0

# 要素の追加(末尾に追加)
float_array.append(5.0)

# イテレーション
for element in float_array:
    print(element)

# 要素へのアクセス
print(float_array[0])  # 出力: 1.0

# スライス
subset = float_array[1:3]  # 2番目から3番目までの要素を取得

# 要素の変更
float_array[1] = 4.0

# 要素の追加(末尾に追加)
float_array.append(5.0)

# イテレーション
for element in float_array:
    print(element)

array オブジェクトは通常のリストと同じようにイテレーションできます。要素の型が指定されているため、それに従って適切な操作を行うことが重要です。例えば、倍精度浮動小数点型の d を指定した場合、array オブジェクトの要素は浮動小数点数として格納されます。

コンストラクター

[編集]

arrayオブジェクトは、arrayモジュールのarray() です。

関数定義
def array(typecode, [inittialize-iteratable]):
arrayのtypecodeと特性
typecode C言語の型 要素のバイト数
'b' signed char 1
'B' unsigned char 1
'u' wchar_t 4
'h' signed short 2
'H' unsigned short 2
'i' signed int 4
'I' unsigned int 4
'l' signed long 8
'L' unsigned long 8
'q' signed long long 8
'Q' unsigned long long 8
'f' float 4
'd' double 8
from array import array, typecodes

print("""\
{| class="wikitable"
|+ arrayのtypecodeと特性
!typecode!!C言語の型!!要素のバイト数\
""")
for typecode, ctype in zip(typecodes,
    "signed char,unsigned char,wchar_t,signed short,unsigned short,signed int,unsigned int,signed long,unsigned long,signed long long,unsigned long long,float,double".split(",")):
    ary = array(typecode, "ABCDEF" if typecode == 'u' else range(10))
    print(f'''\
|-
! {repr(typecode)}
| {ctype} 
|style='text-align:right'| {ary.itemsize}\
''')

print("|}")
コンストラクター
from array import array, typecodes

for typecode in typecodes:
    ary = array(typecode, "ABCDEF" if typecode == 'u' else range(10))
    print(f'''\
{ary.typecode=} type={type(ary[0]).__name__} {ary.itemsize=}
{ary=}
{len(ary)=}
{ary[3]=}
{ary[1:-2]=}
{ary[1:-2:2]=}
{list(ary)=}
{ary.tolist()=}
''')
実行結果
ary.typecode='b' type=int ary.itemsize=1
ary=array('b', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
len(ary)=10
ary[3]=3
ary[1:-2]=array('b', [1, 2, 3, 4, 5, 6, 7])
ary[1:-2:2]=array('b', [1, 3, 5, 7])
list(ary)=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ary.tolist()=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

ary.typecode='B' type=int ary.itemsize=1
ary=array('B', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
len(ary)=10
ary[3]=3
ary[1:-2]=array('B', [1, 2, 3, 4, 5, 6, 7])
ary[1:-2:2]=array('B', [1, 3, 5, 7])
list(ary)=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ary.tolist()=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

ary.typecode='u' type=str ary.itemsize=4
ary=array('u', 'ABCDEF')
len(ary)=6
ary[3]='D'
ary[1:-2]=array('u', 'BCD')
ary[1:-2:2]=array('u', 'BD')
list(ary)=['A', 'B', 'C', 'D', 'E', 'F']
ary.tolist()=['A', 'B', 'C', 'D', 'E', 'F']

ary.typecode='h' type=int ary.itemsize=2
ary=array('h', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
len(ary)=10
ary[3]=3
ary[1:-2]=array('h', [1, 2, 3, 4, 5, 6, 7])
ary[1:-2:2]=array('h', [1, 3, 5, 7])
list(ary)=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ary.tolist()=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

ary.typecode='H' type=int ary.itemsize=2
ary=array('H', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
len(ary)=10
ary[3]=3
ary[1:-2]=array('H', [1, 2, 3, 4, 5, 6, 7])
ary[1:-2:2]=array('H', [1, 3, 5, 7])
list(ary)=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ary.tolist()=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

ary.typecode='i' type=int ary.itemsize=4
ary=array('i', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
len(ary)=10
ary[3]=3
ary[1:-2]=array('i', [1, 2, 3, 4, 5, 6, 7])
ary[1:-2:2]=array('i', [1, 3, 5, 7])
list(ary)=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ary.tolist()=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

ary.typecode='I' type=int ary.itemsize=4
ary=array('I', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
len(ary)=10
ary[3]=3
ary[1:-2]=array('I', [1, 2, 3, 4, 5, 6, 7])
ary[1:-2:2]=array('I', [1, 3, 5, 7])
list(ary)=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ary.tolist()=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

ary.typecode='l' type=int ary.itemsize=8
ary=array('l', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
len(ary)=10
ary[3]=3
ary[1:-2]=array('l', [1, 2, 3, 4, 5, 6, 7])
ary[1:-2:2]=array('l', [1, 3, 5, 7])
list(ary)=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ary.tolist()=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

ary.typecode='L' type=int ary.itemsize=8
ary=array('L', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
len(ary)=10
ary[3]=3
ary[1:-2]=array('L', [1, 2, 3, 4, 5, 6, 7])
ary[1:-2:2]=array('L', [1, 3, 5, 7])
list(ary)=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ary.tolist()=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

ary.typecode='q' type=int ary.itemsize=8
ary=array('q', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
len(ary)=10
ary[3]=3
ary[1:-2]=array('q', [1, 2, 3, 4, 5, 6, 7])
ary[1:-2:2]=array('q', [1, 3, 5, 7])
list(ary)=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ary.tolist()=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

ary.typecode='Q' type=int ary.itemsize=8
ary=array('Q', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
len(ary)=10
ary[3]=3
ary[1:-2]=array('Q', [1, 2, 3, 4, 5, 6, 7])
ary[1:-2:2]=array('Q', [1, 3, 5, 7])
list(ary)=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ary.tolist()=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

ary.typecode='f' type=float ary.itemsize=4
ary=array('f', [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0])
len(ary)=10
ary[3]=3.0
ary[1:-2]=array('f', [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0])
ary[1:-2:2]=array('f', [1.0, 3.0, 5.0, 7.0])
list(ary)=[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
ary.tolist()=[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]

ary.typecode='d' type=float ary.itemsize=8
ary=array('d', [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0])
len(ary)=10
ary[3]=3.0
ary[1:-2]=array('d', [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0])
ary[1:-2:2]=array('d', [1.0, 3.0, 5.0, 7.0])
list(ary)=[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
ary.tolist()=[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]

arrayと演算子

[編集]
arrayと演算子
from array import array

for code in ('b', 'i', 'd'):
    ary = array(code, [i for i in range(10)])
    print(f'''\
{type(ary)=}
{ary=}
{ary+ary=}
{ary*3=}
{3*ary=}
''')
実行結果
li=[10, 'ABC', 30]
li[1]='ABC'
li[-1]=30
li + [2,3,4]=[10, 'ABC', 30, 2, 3, 4]
li * 2=[10, 'ABC', 30, 10, 'ABC', 30]
2 * li=[10, 'ABC', 30, 10, 'ABC', 30]
li == [10 ,"ABC" ,30]=True
li != [10 ,"ABC" ,30]=False
li < [10 ,"ABC" ,30]=False
li > [10 ,"ABC" ,30]=False
arrayの要素は、インデックス演算子で参照できます。
array内の要素の順位はタプルやレンジと同じく、0番から始まります。
負のインデクスiは、len(self)+iを表します。
array同士の足し算は、連結した新しいarrayを返します。
arraytと整数nとの乗算は、tをn回繰り返したarrayを返します。
整数nとarraytとの乗算は、tをn回繰り返したarrayを返します。
array同士は、比較や大小判別ができます。

arrayはミュータブル

[編集]

arrayの各要素を、代入・置き換えすることもできます。

arrayはミュータブル
from array import array

for code in ('b', 'i', 'd'):
    ary = array(code, [i for i in range(10)])
    ary[8] = 100
    print(f'''\
{type(ary)=}
{ary=}
''')
実行結果
type(ary)=<class 'array.array'>
ary=array('b', [0, 1, 2, 3, 4, 5, 6, 7, 100, 9])

type(ary)=<class 'array.array'>
ary=array('i', [0, 1, 2, 3, 4, 5, 6, 7, 100, 9])

type(ary)=<class 'array.array'>
ary=array('d', [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 100.0, 9.0])

arrayのフィールド一覧

[編集]
arrayのフィールド一覧
from array import array

for code in ('b', 'i', 'd'):
    ary = array(code, [i for i in range(10)])
    print(f'''\
{type(ary)=}
{ary=}
''')
    for i in dir(ary):
        print(i, eval(f"type({ary}.{i})"))
実行結果
type(ary)=<class 'array.array'>
ary=array('b', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

__add__ <class 'method-wrapper'>
__class__ <class 'type'>
__contains__ <class 'method-wrapper'>
__copy__ <class 'builtin_function_or_method'>
__deepcopy__ <class 'builtin_function_or_method'>
__delattr__ <class 'method-wrapper'>
__delitem__ <class 'method-wrapper'>
__dir__ <class 'builtin_function_or_method'>
__doc__ <class 'str'>
__eq__ <class 'method-wrapper'>
__format__ <class 'builtin_function_or_method'>
__ge__ <class 'method-wrapper'>
__getattribute__ <class 'method-wrapper'>
__getitem__ <class 'method-wrapper'>
__gt__ <class 'method-wrapper'>
__hash__ <class 'NoneType'>
__iadd__ <class 'method-wrapper'>
__imul__ <class 'method-wrapper'>
__init__ <class 'method-wrapper'>
__init_subclass__ <class 'builtin_function_or_method'>
__iter__ <class 'method-wrapper'>
__le__ <class 'method-wrapper'>
__len__ <class 'method-wrapper'>
__lt__ <class 'method-wrapper'>
__mul__ <class 'method-wrapper'>
__ne__ <class 'method-wrapper'>
__new__ <class 'builtin_function_or_method'>
__reduce__ <class 'builtin_function_or_method'>
__reduce_ex__ <class 'builtin_function_or_method'>
__repr__ <class 'method-wrapper'>
__rmul__ <class 'method-wrapper'>
__setattr__ <class 'method-wrapper'>
__setitem__ <class 'method-wrapper'>
__sizeof__ <class 'builtin_function_or_method'>
__str__ <class 'method-wrapper'>
__subclasshook__ <class 'builtin_function_or_method'>
append <class 'builtin_function_or_method'>
buffer_info <class 'builtin_function_or_method'>
byteswap <class 'builtin_function_or_method'>
count <class 'builtin_function_or_method'>
extend <class 'builtin_function_or_method'>
frombytes <class 'builtin_function_or_method'>
fromfile <class 'builtin_function_or_method'>
fromlist <class 'builtin_function_or_method'>
fromstring <class 'builtin_function_or_method'>
fromunicode <class 'builtin_function_or_method'>
index <class 'builtin_function_or_method'>
insert <class 'builtin_function_or_method'>
itemsize <class 'int'>
pop <class 'builtin_function_or_method'>
remove <class 'builtin_function_or_method'>
reverse <class 'builtin_function_or_method'>
tobytes <class 'builtin_function_or_method'>
tofile <class 'builtin_function_or_method'>
tolist <class 'builtin_function_or_method'>
tostring <class 'builtin_function_or_method'>
tounicode <class 'builtin_function_or_method'>
typecode <class 'str'>
type(ary)=<class 'array.array'>
ary=array('i', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

__add__ <class 'method-wrapper'>
__class__ <class 'type'>
__contains__ <class 'method-wrapper'>
__copy__ <class 'builtin_function_or_method'>
__deepcopy__ <class 'builtin_function_or_method'>
__delattr__ <class 'method-wrapper'>
__delitem__ <class 'method-wrapper'>
__dir__ <class 'builtin_function_or_method'>
__doc__ <class 'str'>
__eq__ <class 'method-wrapper'>
__format__ <class 'builtin_function_or_method'>
__ge__ <class 'method-wrapper'>
__getattribute__ <class 'method-wrapper'>
__getitem__ <class 'method-wrapper'>
__gt__ <class 'method-wrapper'>
__hash__ <class 'NoneType'>
__iadd__ <class 'method-wrapper'>
__imul__ <class 'method-wrapper'>
__init__ <class 'method-wrapper'>
__init_subclass__ <class 'builtin_function_or_method'>
__iter__ <class 'method-wrapper'>
__le__ <class 'method-wrapper'>
__len__ <class 'method-wrapper'>
__lt__ <class 'method-wrapper'>
__mul__ <class 'method-wrapper'>
__ne__ <class 'method-wrapper'>
__new__ <class 'builtin_function_or_method'>
__reduce__ <class 'builtin_function_or_method'>
__reduce_ex__ <class 'builtin_function_or_method'>
__repr__ <class 'method-wrapper'>
__rmul__ <class 'method-wrapper'>
__setattr__ <class 'method-wrapper'>
__setitem__ <class 'method-wrapper'>
__sizeof__ <class 'builtin_function_or_method'>
__str__ <class 'method-wrapper'>
__subclasshook__ <class 'builtin_function_or_method'>
append <class 'builtin_function_or_method'>
buffer_info <class 'builtin_function_or_method'>
byteswap <class 'builtin_function_or_method'>
count <class 'builtin_function_or_method'>
extend <class 'builtin_function_or_method'>
frombytes <class 'builtin_function_or_method'>
fromfile <class 'builtin_function_or_method'>
fromlist <class 'builtin_function_or_method'>
fromstring <class 'builtin_function_or_method'>
fromunicode <class 'builtin_function_or_method'>
index <class 'builtin_function_or_method'>
insert <class 'builtin_function_or_method'>
itemsize <class 'int'>
pop <class 'builtin_function_or_method'>
remove <class 'builtin_function_or_method'>
reverse <class 'builtin_function_or_method'>
tobytes <class 'builtin_function_or_method'>
tofile <class 'builtin_function_or_method'>
tolist <class 'builtin_function_or_method'>
tostring <class 'builtin_function_or_method'>
tounicode <class 'builtin_function_or_method'>
typecode <class 'str'>
type(ary)=<class 'array.array'>
ary=array('d', [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0])

__add__ <class 'method-wrapper'>
__class__ <class 'type'>
__contains__ <class 'method-wrapper'>
__copy__ <class 'builtin_function_or_method'>
__deepcopy__ <class 'builtin_function_or_method'>
__delattr__ <class 'method-wrapper'>
__delitem__ <class 'method-wrapper'>
__dir__ <class 'builtin_function_or_method'>
__doc__ <class 'str'>
__eq__ <class 'method-wrapper'>
__format__ <class 'builtin_function_or_method'>
__ge__ <class 'method-wrapper'>
__getattribute__ <class 'method-wrapper'>
__getitem__ <class 'method-wrapper'>
__gt__ <class 'method-wrapper'>
__hash__ <class 'NoneType'>
__iadd__ <class 'method-wrapper'>
__imul__ <class 'method-wrapper'>
__init__ <class 'method-wrapper'>
__init_subclass__ <class 'builtin_function_or_method'>
__iter__ <class 'method-wrapper'>
__le__ <class 'method-wrapper'>
__len__ <class 'method-wrapper'>
__lt__ <class 'method-wrapper'>
__mul__ <class 'method-wrapper'>
__ne__ <class 'method-wrapper'>
__new__ <class 'builtin_function_or_method'>
__reduce__ <class 'builtin_function_or_method'>
__reduce_ex__ <class 'builtin_function_or_method'>
__repr__ <class 'method-wrapper'>
__rmul__ <class 'method-wrapper'>
__setattr__ <class 'method-wrapper'>
__setitem__ <class 'method-wrapper'>
__sizeof__ <class 'builtin_function_or_method'>
__str__ <class 'method-wrapper'>
__subclasshook__ <class 'builtin_function_or_method'>
append <class 'builtin_function_or_method'>
buffer_info <class 'builtin_function_or_method'>
byteswap <class 'builtin_function_or_method'>
count <class 'builtin_function_or_method'>
extend <class 'builtin_function_or_method'>
frombytes <class 'builtin_function_or_method'>
fromfile <class 'builtin_function_or_method'>
fromlist <class 'builtin_function_or_method'>
fromstring <class 'builtin_function_or_method'>
fromunicode <class 'builtin_function_or_method'>
index <class 'builtin_function_or_method'>
insert <class 'builtin_function_or_method'>
itemsize <class 'int'>
pop <class 'builtin_function_or_method'>
remove <class 'builtin_function_or_method'>
reverse <class 'builtin_function_or_method'>
tobytes <class 'builtin_function_or_method'>
tofile <class 'builtin_function_or_method'>
tolist <class 'builtin_function_or_method'>
tostring <class 'builtin_function_or_method'>
tounicode <class 'builtin_function_or_method'>
typecode <class 'str'>

脚註

[編集]
  1. ^ 3.10.1 Documentation » The Python Standard Library » Data Types » array — Efficient arrays of numeric values” (2021年12月16日). 2021年12月16日閲覧。

辞書

[編集]

Pythonの辞書(Dictionary)は、任意個のキーとコレクションです。

コンストラクターとリテラル

[編集]
リストリテラル
print(f"""\
{ {}=}
{ dict()=}
{ dict(((1, 1),(2, 4),(3,9)))=}
{ dict((i,2**i) for i in range(5))=}
{ {i:2**i for i in range(5)}=}
{ {10,"ABC", 20, "XYZ"}=}
{ {1:"one", 2:"two",3:"three"}=}
{ {
    1: "壱",
    2: "弐",
    3: "参"
    }=}
""")
実行結果
{}={}
 dict()={}
 dict(((1, 1),(2, 4),(3,9)))={1: 1, 2: 4, 3: 9}
 dict((i,2**i) for i in range(5))={0: 1, 1: 2, 2: 4, 3: 8, 4: 16}
 {i:2**i for i in range(5)}={0: 1, 1: 2, 2: 4, 3: 8, 4: 16}
 {10,"ABC", 20, "XYZ"}={10, 'XYZ', 'ABC', 20}
 {1:"one", 2:"two",3:"three"}={1: 'one', 2: 'two', 3: 'three'}
 {
    1: "壱",
    2: "弐",
    3: "参"
    }={1: '壱', 2: '弐', 3: '参'}
空の辞書は、空の辞書リテラル {} あるいはコンストラクターである組込み関数dict()を引数無しで呼出し生成します。
dict()の引数は、キーと値をを要素とするコレクションを要素とするコレクションです(文章だとややこしいですが、dict(((1, 1),(2, 4),(3,9)))=={1: 1, 2: 4, 3: 9}です)。
dict()には、ジェネレーション式などのイテレーターを渡す事もできます(dict((i,2**i) for i in range(5))=={0: 1, 1: 2, 2: 4, 3: 8, 4: 16}
辞書にも内包表記があります({i:2**i for i in range(5)}=={0: 1, 1: 2, 2: 4, 3: 8, 4: 16})。
辞書リテラルは、キーと値を : で区切ったペアをカンマ , で区切り、全体を { } で囲みます(: を , と間違えると(エラーにならず)セット(集合)のリテラルになり、気が付き遅れがちです。逆に {} を空集合∅のつもりで書き、辞書であることに気づかないケースもあります)。

キーの重複

[編集]

Pythonでは、辞書のキーの重複は許されず、最後の値で上書きされます。 これは辞書リテラルにも当てはまり、同じキーの最も右の値がリテラル内のキーの値となります[1]

キーが重複した辞書リテラル
# 国語が重複している
dic = {"国語": 80, "氏名": "山田タロウ", "国語": 70 }

print(dic["国語"])
print(dic)
実行結果
70
{'国語': 70, '氏名': '山田タロウ'}
Pythinの辞書は順位を保存するので、重複したキーの効果の痕跡が順位に出ています。

辞書のフィールド一覧

[編集]
辞書のフィールド一覧
obj = dict()
for i in dir(obj):
    print(i, eval(f"type({obj}.{i})"))
実行結果
__class__ <class 'type'>
__contains__ <class 'builtin_function_or_method'>
__delattr__ <class 'method-wrapper'>
__delitem__ <class 'method-wrapper'>
__dir__ <class 'builtin_function_or_method'>
__doc__ <class 'str'>
__eq__ <class 'method-wrapper'>
__format__ <class 'builtin_function_or_method'>
__ge__ <class 'method-wrapper'>
__getattribute__ <class 'method-wrapper'>
__getitem__ <class 'builtin_function_or_method'>
__gt__ <class 'method-wrapper'>
__hash__ <class 'NoneType'>
__init__ <class 'method-wrapper'>
__init_subclass__ <class 'builtin_function_or_method'>
__iter__ <class 'method-wrapper'>
__le__ <class 'method-wrapper'>
__len__ <class 'method-wrapper'>
__lt__ <class 'method-wrapper'>
__ne__ <class 'method-wrapper'>
__new__ <class 'builtin_function_or_method'>
__reduce__ <class 'builtin_function_or_method'>
__reduce_ex__ <class 'builtin_function_or_method'>
__repr__ <class 'method-wrapper'>
__reversed__ <class 'builtin_function_or_method'>
__setattr__ <class 'method-wrapper'>
__setitem__ <class 'method-wrapper'>
__sizeof__ <class 'builtin_function_or_method'>
__str__ <class 'method-wrapper'>
__subclasshook__ <class 'builtin_function_or_method'>
clear <class 'builtin_function_or_method'>
copy <class 'builtin_function_or_method'>
fromkeys <class 'builtin_function_or_method'>
get <class 'builtin_function_or_method'>
items <class 'builtin_function_or_method'>
keys <class 'builtin_function_or_method'>
pop <class 'builtin_function_or_method'>
popitem <class 'builtin_function_or_method'>
setdefault <class 'builtin_function_or_method'>
update <class 'builtin_function_or_method'>
values <class 'builtin_function_or_method'>

脚註

[編集]
  1. ^ Python 3.10.6 Documentation » The Python Language Reference » 6. Expressions » 6.2.7. Dictionary displays”. 2022年8月10日閲覧。 “If a comma-separated sequence of key/datum pairs is given, they are evaluated from left to right to define the entries of the dictionary: each key object is used as a key into the dictionary to store the corresponding datum. This means that you can specify the same key multiple times in the key/datum list, and the final dictionary’s value for that key will be the last one given.

    カンマで区切られた一連のキー/データペアが与えられると、それらは左から右へと評価されて辞書のエントリーを定義します。各キーオブジェクトは、対応するデータを格納する辞書のキーとして使用されます。つまり、key/datumリストで同じキーを複数回指定しても、そのキーに対する最終的な辞書の値は、最後に指定されたものになります。”

セット

[編集]

セット(set; 集合)は、一意で不変のオブジェクトの、順不同の有限集合を表します。 そのため、どのような添え字でもインデックスを付けることはできません。 しかし、反復処理することは可能で、組込み関数len() は、セット内のアイテムの数を返します。 集合の一般的な用途は、高速なメンバーシップテスト、シーケンスからの重複の除去、および交叉、和集合、差集合、対称差などの数学的操作の計算です[1]

コンストラクターとリテラルと内包表記

[編集]
コンストラクターとリテラル
print(f'''\
{ set()=}
{ set([10,20,30,10])=}
{ set(range(10))=}
{ {10, "ABC", 30}=}
{ {i for i in range(10)}=}
{ {(1,"one"), (2,"two"),(3,"three"),(1,"one")}=}
{ {
    (1,"壱"),
    (2,"弐"),
    (3,"参"),
    (1,"壱"),
    }=}
{ {1,6,2,4,2,6,2,3}=}\
''')
実行結果
 set()=set()
 set([10,20,30,10])={10, 20, 30}
 set(range(10))={0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
 {10, "ABC", 30}={'ABC', 10, 30}
 {i for i in range(10)}={0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
 {(1,"one"), (2,"two"),(3,"three"),(1,"one")}={(3, 'three'), (2, 'two'), (1, 'one')}
 {
    (1,"壱"),
    (2,"弐"),
    (3,"参"),
    (1,"壱"),
    }={(3, '参'), (1, '壱'), (2, '弐')}
 {1,6,2,4,2,6,2,3}={1, 2, 3, 4, 6}
空のセットは、コンストラクターである組込み関数setを引数無しで呼び出し生成します({}は辞書になります)。
コンストラクターにイテレータブルオブジェクトを渡すと、イテレータブルオブジェクトの要素の集合をかえします(この場合も重複排除が働きます)。
セットリテラルは、要素をカンマ , で区切り全体を波括弧 { } で囲みます。
セットにも内包表記があり、{ 式 for 変数 in イテレーター }の形式です。

セットと演算子

[編集]
セットと演算子
s1 = {10, "ABC", 30}

print(
    f"""\
{s1=}
{s1 - {10, 20, 30}=}
{s1 | {2, 3, 4}=}
{s1 & {10, 20, 30}=}
{s1 ^ {10, 20, 30}=}
{s1 == {10 ,"ABC" ,30}=}
{s1 != {10 ,"ABC" ,30}=}
{s1 > {10 ,"ABC" ,30}=}
{s1 < {10 ,"ABC" ,30}=}
"""
)
実行結果
s1={10, 'ABC', 30}
s1 - {10, 20, 30}={'ABC'}
s1 | {2, 3, 4}={2, 3, 'ABC', 4, 10, 30}
s1 & {10, 20, 30}={10, 30}
s1 ^ {10, 20, 30}={20, 'ABC'}
s1 == {10 ,"ABC" ,30}=True
s1 != {10 ,"ABC" ,30}=False
s1 > {10 ,"ABC" ,30}=False
s1 < {10 ,"ABC" ,30}=False
セット同士の減算は、差集合を返します。
セット同士の論理和( + や or ではなく | )は、和集合を返します。
セット同士の論理積( * や and ではなく & )は、交叉を返します。
セット同士の排他的論理和( xor ではなく ^ )は、対称差を返します。
セット同士は、比較や大小判別ができます。

演算子形式とメソッド形式

[編集]
演算子形式とメソッド形式
s = {i for i in range(10)}
e = {i for i in range(10) if i % 2 == 0}
o = {i for i in range(10) if i % 2 != 0}

print(f"""\
{ s=}
{ e=}
{ o=}
{ len(s)=} # 集合の濃度
{ 3 in s=} # 3は集合sに含まれるか
{ 10 not in s=} # 10は集合sに含まれ**ない**か
{ e | o == s =} # 0..9の偶数と0..9の奇数の和集合は、0..9に等しいか?
{ e.union(o) == s =} # 0..9の偶数と0..9の奇数の和集合は、0..9に等しいか?
{ {0,3,6,9}.union({1,4,7}, {2,5,8}) == s =} # unionは2つ以上引数を持てる
{ s - e == o =} # 0..9と0..9の偶数の差集合は、0..9の奇数に等しいか?
{ s.difference(e) == o =} # 0..9と0..9の偶数の差集合は、0..9の奇数に等しいか?
{ s.difference(e,o) =} # differenceは2つ以上引数を持てる
{ e ^ o == s =} # 0..9の偶数と0..9の奇数の和集合は、0..9に等しいか?
{ e.symmetric_difference(o) == s =} # 0..9の偶数と0..9の奇数の和集合は、0..9に等しいか?
{ {1,3,5}.isdisjoint({2,4,6})=} # 共通要素がない
{ {1,2,3}.isdisjoint({2,4,6})=} # 要素2が共通
{ e.issubset(s)=} # eはsの部分集合
{ e <= s=} # eはsの部分集合?
{ e < s=} # eはsの真部分集合?
{ o < s=} # oはsの真部分集合?
{ o | e < s=} # oとeの和集合はsの真部分集合?\
""")
実行結果
s={0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
 e={0, 2, 4, 6, 8}
 o={1, 3, 5, 7, 9}
 len(s)=10 # 集合の濃度
 3 in s=True # 3は集合sに含まれるか
 10 not in s=True # 10は集合sに含まれ**ない**か
 e | o == s =True # 0..9の偶数と0..9の奇数の和集合は、0..9に等しいか?
 e.union(o) == s =True # 0..9の偶数と0..9の奇数の和集合は、0..9に等しいか?
 {0,3,6,9}.union({1,4,7}, {2,5,8}) == s =True # unionは2つ以上引数を持てる
 s - e == o =True # 0..9と0..9の偶数の差集合は、0..9の奇数に等しいか?
 s.difference(e) == o =True # 0..9と0..9の偶数の差集合は、0..9の奇数に等しいか?
 s.difference(e,o) =set() # differenceは2つ以上引数を持てる
 e ^ o == s =True # 0..9の偶数と0..9の奇数の和集合は、0..9に等しいか?
 e.symmetric_difference(o) == s =True # 0..9の偶数と0..9の奇数の和集合は、0..9に等しいか?
 {1,3,5}.isdisjoint({2,4,6})=True # 共通要素がない
 {1,2,3}.isdisjoint({2,4,6})=False # 要素2が共通
 e.issubset(s)=True # eはsの部分集合
 e <= s=True # eはsの部分集合?
 e < s=True # eはsの真部分集合?
 o < s=True # oはsの真部分集合?
 o | e < s=False # oとeの和集合はsの真部分集合?

メソッド keys(), values(), items()の返すオブジェクト

[編集]

keys(), values(), items()の返すオブジェクトは、それぞれキー、値、キーと値のペアーのタプルのイテレータブルですが、関数から返った値は辞書とその後も結びついています(これらのオブジェクトをセット・ビュー オブジェクトと呼びます)。 リストのように静的なオブジェクトではありません。

メソッド keys(), values(), items()の返す値
a = { 1:"one",2:"two", 3:"three"}
k = a.keys()
v = a.values()
i = a.items()
print(f"{a=}\n{k=}\n{v=}\n{i=}\n")

a[0] = "zero"

print(f"{a=}\n{k=}\n{v=}\n{i=}\n")

del a[1]

print(f"{a=}\n{k=}\n{v=}\n{i=}\n")
実行結果
a={1: 'one', 2: 'two', 3: 'three'}
k=dict_keys([1, 2, 3])
v=dict_values(['one', 'two', 'three'])
i=dict_items([(1, 'one'), (2, 'two'), (3, 'three')])

a={1: 'one', 2: 'two', 3: 'three', 0: 'zero'}
k=dict_keys([1, 2, 3, 0])
v=dict_values(['one', 'two', 'three', 'zero'])
i=dict_items([(1, 'one'), (2, 'two'), (3, 'three'), (0, 'zero')])

a={2: 'two', 3: 'three', 0: 'zero'}
k=dict_keys([2, 3, 0])
v=dict_values(['two', 'three', 'zero'])
i=dict_items([(2, 'two'), (3, 'three'), (0, 'zero')])

破壊的メソッド

[編集]

破壊的メソッドは、レシーバーであるセットオブジェクト自体を変更するメソッドです。

破壊的メソッド
a = {1,2,3}     
print(f"a = {1,2,3}\n{ a=}")
a.add(4)        
print(f"a.add(4)\n {a=}")
a.remove(2)     
print(f"a.remove(2)\n {a=}")
try:
    a.remove(0) 
    print(f"a.remove(0)\n {a=}")
except KeyError as e:
    print(type(e).__name__, e)
a.discard(0)    
print(f"a.discard(0)\n {a=}")
b = a.copy()    
print(f"b = a.copy()\n {b=}")
try:
    while True:    
        print(f"{a.pop()}", end=", ")
except KeyError as e:
    print(type(e).__name__, e)
print(f" {a=}, {b=}")
b.clear()       
print(f"b.clear()\n {b=}")
実行結果
a = (1, 2, 3)
 a={1, 2, 3}
a.add(4)
 a={1, 2, 3, 4}
a.remove(2)
 a={1, 3, 4}
KeyError 0
a.discard(0)
 a={1, 3, 4}
b = a.copy()
 b={1, 3, 4}
1, 3, 4, KeyError 'pop from an empty set'
 a=set(), b={1, 3, 4}
b.clear()
 b=set()

セットのフィールド一覧

[編集]
セットのフィールド一覧
obj = set()
for i in dir(obj):
    print(i, 
        eval(f"type({obj}.{i}).__name__"),
        eval(f"({obj}.{i}).__doc__"),
        sep=", "
        )
実行結果
__and__, method-wrapper, Return self&value.
__class__, type, set() -> new empty set object
set(iterable) -> new set object

Build an unordered collection of unique elements.
__contains__, builtin_function_or_method, x.__contains__(y) <==> y in x.
__delattr__, method-wrapper, Implement delattr(self, name).
__dir__, builtin_function_or_method, Default dir() implementation.
__doc__, str, str(object='') -> str
str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or
errors is specified, then the object must expose a data buffer
that will be decoded using the given encoding and error handler.
Otherwise, returns the result of object.__str__() (if defined)
or repr(object).
encoding defaults to sys.getdefaultencoding().
errors defaults to 'strict'.
__eq__, method-wrapper, Return self==value.
__format__, builtin_function_or_method, Default object formatter.
__ge__, method-wrapper, Return self>=value.
__getattribute__, method-wrapper, Return getattr(self, name).
__gt__, method-wrapper, Return self>value.
__hash__, NoneType, None
__iand__, method-wrapper, Return self&=value.
__init__, method-wrapper, Initialize self.  See help(type(self)) for accurate signature.
__init_subclass__, builtin_function_or_method, This method is called when a class is subclassed.

The default implementation does nothing. It may be
overridden to extend subclasses.

__ior__, method-wrapper, Return self|=value.
__isub__, method-wrapper, Return self-=value.
__iter__, method-wrapper, Implement iter(self).
__ixor__, method-wrapper, Return self^=value.
__le__, method-wrapper, Return self<=value.
__len__, method-wrapper, Return len(self).
__lt__, method-wrapper, Return self<value.
__ne__, method-wrapper, Return self!=value.
__new__, builtin_function_or_method, Create and return a new object.  See help(type) for accurate signature.
__or__, method-wrapper, Return self|value.
__rand__, method-wrapper, Return value&self.
__reduce__, builtin_function_or_method, Return state information for pickling.
__reduce_ex__, builtin_function_or_method, Helper for pickle.
__repr__, method-wrapper, Return repr(self).
__ror__, method-wrapper, Return value|self.
__rsub__, method-wrapper, Return value-self.
__rxor__, method-wrapper, Return value^self.
__setattr__, method-wrapper, Implement setattr(self, name, value).
__sizeof__, builtin_function_or_method, S.__sizeof__() -> size of S in memory, in bytes
__str__, method-wrapper, Return str(self).
__sub__, method-wrapper, Return self-value.
__subclasshook__, builtin_function_or_method, Abstract classes can override this to customize issubclass().

This is invoked early on by abc.ABCMeta.__subclasscheck__().
It should return True, False or NotImplemented.  If it returns
NotImplemented, the normal algorithm is used.  Otherwise, it
overrides the normal algorithm (and the outcome is cached).

__xor__, method-wrapper, Return self^value.
add, builtin_function_or_method, Add an element to a set.

This has no effect if the element is already present.
clear, builtin_function_or_method, Remove all elements from this set.
copy, builtin_function_or_method, Return a shallow copy of a set.
difference, builtin_function_or_method, Return the difference of two or more sets as a new set.

(i.e. all elements that are in this set but not the others.)
difference_update, builtin_function_or_method, Remove all elements of another set from this set.
discard, builtin_function_or_method, Remove an element from a set if it is a member.

If the element is not a member, do nothing.
intersection, builtin_function_or_method, Return the intersection of two sets as a new set.

(i.e. all elements that are in both sets.)
intersection_update, builtin_function_or_method, Update a set with the intersection of itself and another.
isdisjoint, builtin_function_or_method, Return True if two sets have a null intersection.
issubset, builtin_function_or_method, Report whether another set contains this set.
issuperset, builtin_function_or_method, Report whether this set contains another set.
pop, builtin_function_or_method, Remove and return an arbitrary set element.
Raises KeyError if the set is empty.
remove, builtin_function_or_method, Remove an element from a set; it must be a member.

If the element is not a member, raise a KeyError.
symmetric_difference, builtin_function_or_method, Return the symmetric difference of two sets as a new set.

(i.e. all elements that are in exactly one of the sets.)
symmetric_difference_update, builtin_function_or_method, Update a set with the symmetric difference of itself and another.
union, builtin_function_or_method, Return the union of sets as a new set.

(i.e. all elements that are in either set.)
update, builtin_function_or_method, Update a set with the union of itself and others.

脚註

[編集]
  1. ^ 3.10.1 Documentation » The Python Language Reference » 3. Data model ¶3.2. The standard type hierarchy” (2021年12月16日). 2021年12月16日閲覧。


モジュール

[編集]

モジュール化(modularization / modularize)は、全体をいくつかの構成単位に分割し、問題の規模と質を低減する分割統治法(divide-and-conquer method)の一つです。 Pythonでは、パッケージ(package)とモジュール(module)がモジュール化の実現に用いられます。 このうち、パッケージはモジュールの構造的な整理手段と考えられ、まずモジュールの用途・用法について解説し、モジュールをユーザーが定義する具体的な例も示します。

モジュールmath

[編集]

平方根などの数学に関する関数を使用したい場合は、モジュールmathをインポートします。

モジュールmathの関数「sqrt()」を使い平方根を求める
import math

print(math.sqrt(2))

help(math.sqrt)
実行結果
1.4142135623730951
Help on built-in function sqrt in module math:

sqrt(x, /)
    Return the square root of x.
構文
import モジュール名

また、インポートされた関数をつかうときは、どのモジュールに由来する関数かを、pythonが判断できるようにするために、「math.sqrt()」のように、関数の前にモジュール名を書きます。 「.」はドット記号です。つまり、「モジュール名.関数名」のような書式になります。

モジュールmathでは、三角関数や指数関数なども、使えます。三角関数の単位は、ラジアンです。

※ ラジアンは弧度法の角度の単位で記号は rad です。とはなにか、高校で習います。度数法で円周は360°ですが、弧度法では2π rad です。
モジュールmathの関数「sin()」を使い正弦を求める
import math

print(math.sin(math.pi/4))
実行結果
0.7071067811865475

モジュールmathの属性一覧

[編集]
モジュールmathの属性一覧
import math

mod = math
print(f"""\
{{| class="wikitable"
|+ {type(mod).__name__} {mod.__name__}の属性一覧
|-
!属性!!値!!__doc__\
""")

for k,v in vars(mod).items():
    print(f"""\
|-
! {k}
| {repr(v)}
| {getattr(v, "__doc__").splitlines()[0]}\
""")
print("|}}")
module mathの属性一覧
属性 __doc__
__name__ 'math' str(object=) -> str
__doc__ 'This module provides access to the mathematical functions\ndefined by the C standard.' str(object=) -> str
__package__ str(object=) -> str
__loader__ <class '_frozen_importlib.BuiltinImporter'> Meta path import for built-in modules.
__spec__ ModuleSpec(name='math', loader=<class '_frozen_importlib.BuiltinImporter'>, origin='built-in') The specification for a module, used for loading.
acos <built-in function acos> Return the arc cosine (measured in radians) of x.
acosh <built-in function acosh> Return the inverse hyperbolic cosine of x.
asin <built-in function asin> Return the arc sine (measured in radians) of x.
asinh <built-in function asinh> Return the inverse hyperbolic sine of x.
atan <built-in function atan> Return the arc tangent (measured in radians) of x.
atan2 <built-in function atan2> Return the arc tangent (measured in radians) of y/x.
atanh <built-in function atanh> Return the inverse hyperbolic tangent of x.
ceil <built-in function ceil> Return the ceiling of x as an Integral.
copysign <built-in function copysign> Return a float with the magnitude (absolute value) of x but the sign of y.
cos <built-in function cos> Return the cosine of x (measured in radians).
cosh <built-in function cosh> Return the hyperbolic cosine of x.
degrees <built-in function degrees> Convert angle x from radians to degrees.
dist <built-in function dist> Return the Euclidean distance between two points p and q.
erf <built-in function erf> Error function at x.
erfc <built-in function erfc> Complementary error function at x.
exp <built-in function exp> Return e raised to the power of x.
expm1 <built-in function expm1> Return exp(x)-1.
fabs <built-in function fabs> Return the absolute value of the float x.
factorial <built-in function factorial> Find x!.
floor <built-in function floor> Return the floor of x as an Integral.
fmod <built-in function fmod> Return fmod(x, y), according to platform C.
frexp <built-in function frexp> Return the mantissa and exponent of x, as pair (m, e).
fsum <built-in function fsum> Return an accurate floating point sum of values in the iterable seq.
gamma <built-in function gamma> Gamma function at x.
gcd <built-in function gcd> greatest common divisor of x and y
hypot <built-in function hypot> hypot(*coordinates) -> value
isclose <built-in function isclose> Determine whether two floating point numbers are close in value.
isfinite <built-in function isfinite> Return True if x is neither an infinity nor a NaN, and False otherwise.
isinf <built-in function isinf> Return True if x is a positive or negative infinity, and False otherwise.
isnan <built-in function isnan> Return True if x is a NaN (not a number), and False otherwise.
isqrt <built-in function isqrt> Return the integer part of the square root of the input.
ldexp <built-in function ldexp> Return x * (2**i).
lgamma <built-in function lgamma> Natural logarithm of absolute value of Gamma function at x.
log <built-in function log> log(x, [base=math.e])
log1p <built-in function log1p> Return the natural logarithm of 1+x (base e).
log10 <built-in function log10> Return the base 10 logarithm of x.
log2 <built-in function log2> Return the base 2 logarithm of x.
modf <built-in function modf> Return the fractional and integer parts of x.
pow <built-in function pow> Return x**y (x to the power of y).
radians <built-in function radians> Convert angle x from degrees to radians.
remainder <built-in function remainder> Difference between x and the closest integer multiple of y.
sin <built-in function sin> Return the sine of x (measured in radians).
sinh <built-in function sinh> Return the hyperbolic sine of x.
sqrt <built-in function sqrt> Return the square root of x.
tan <built-in function tan> Return the tangent of x (measured in radians).
tanh <built-in function tanh> Return the hyperbolic tangent of x.
trunc <built-in function trunc> Truncates the Real x to the nearest Integral toward 0.
prod <built-in function prod> Calculate the product of all the elements in the input iterable.
perm <built-in function perm> Number of ways to choose k items from n items without repetition and with order.
comb <built-in function comb> Number of ways to choose k items from n items without repetition and without order.
pi 3.141592653589793 Convert a string or number to a floating point number, if possible.
e 2.718281828459045 Convert a string or number to a floating point number, if possible.
tau 6.283185307179586 Convert a string or number to a floating point number, if possible.
inf inf Convert a string or number to a floating point number, if possible.
nan nan Convert a string or number to a floating point number, if possible.

モジュールrandom

[編集]

サイコロの目のような、乱数をつかうには、モジュールrandomをインポートします。

モジュールmathの関数「sqrt()」を使い乱数を得る
import random

for _ in range(32):
    print(random.randint(1, 6), end=" ")
実行結果
1 2 3 1 3 6 3 3 5 6 4 5 2 1 5 2 2 2 4 4 5 1 2 6 5 5 1 2 1 5 3 5
randint(a, b)により、a以上でb以下の整数を、不規則に表示することができます。

ローカル名前空間へのインポート

[編集]

たとえばモジュールmathから、sqrtだけをローカル名前空間へインポートしたい場合、コードが次のようになります。

mathで定義されているsqrtを全てローカル名前空間にインポート
from math import sqrt

a = sqrt(2)
print(a)
実行結果
1.4142135623730951
構文
from モジュール名 import インポートする識別子
の書式により、特定の関数だけを選んでインポートできます。
ローカル名前空間にインポートした識別子は、「math.」をつけず、そのまま「sqrt(2)」のように呼び出せます。
mathで定義されている識別子を全てローカル名前空間にインポート
from math import *

print(f"{sqrt(2)=}")
print(f"{pi =}")
実行結果
sqrt(2)=1.4142135623730951
pi =3.141592653589793
* を指定しても、アンダースコア _ で始まる識別子はインポートされません。

ユーザー定義モジュール

[編集]

ここまでは、標準ライブラリーのモジュールを紹介してきましたが、モジュールはユーザー自身で定義することもできます。

モジュール定義

[編集]

ここでは、与えられた数が素数か否かを判定するモジュール isprime を作ってみましょう。

isprime.py
"""
isprime:
  Determine if a given number is prime
Usage:
  import isprime
  
  isprime.isprime(42)
  
    OR

  from isprime import isprime
  
  isprime(4423)
"""


_primes = set()
_noprimes = set()

def isprime(x :int) -> bool :
    '''
    >>> isprime(2)
    True
    >>> isprime(10)
    False
    '''
    if x in _primes:
        return True
    if x in _noprimes:
        return False
    if x <= 1:
        return False
    i = 2
    while i*i <= x:
        if x%i == 0:
            _noprimes.add(x)
            return False
        i += 1
    _primes.add(x)
    return True

if __name__ == '__main__':
    assert not isprime(-1)
    assert not isprime(0)
    assert not isprime(1)
    assert isprime(2)
    assert isprime(3)
    assert not isprime(4)
    help(isprime)
アンダースコア _ で始まる識別子は、from MODULE import * でローカル名前空間に読み込まれません。
過去に素数判定を行った履歴を残し、履歴に残った判定結果を再利用するためにだけ使うので、アンダースコア _ を前置してモジュール内だけで使うことを表しました[1]
isprimeだけがモジュール外から可視化された識別子となります。
if __name__ == '__main__':以下は、このファイルがモジュールではなく、メインスクリプトとして実行されたときに評価され、回帰テストなどを書くことが一般的です。

モジュールのインポートと識別子を使った参照

[編集]
Main.py
import isprime

hash = {}
for x in range(100):
    hash[x] = isprime.isprime(x)
print(hash)

help(isprime)
実行結果
{0: False, 1: False, 2: True, 3: True, 4: False, 5: True, 6: False, 7: True, 8: False, 9: False, 10: False, 11: True, 12: False, 13: True, 14: False, 15: False, 16: False, 17: True, 18: False, 19: True, 20: False, 21: False, 22: False, 23: True, 24: False, 25: False, 26: False, 27: False, 28: False, 29: True, 30: False, 31: True, 32: False, 33: False, 34: False, 35: False, 36: False, 37: True, 38: False, 39: False, 40: False, 41: True, 42: False, 43: True, 44: False, 45: False, 46: False, 47: True, 48: False, 49: False, 50: False, 51: False, 52: False, 53: True, 54: False, 55: False, 56: False, 57: False, 58: False, 59: True, 60: False, 61: True, 62: False, 63: False, 64: False, 65: False, 66: False, 67: True, 68: False, 69: False, 70: False, 71: True, 72: False, 73: True, 74: False, 75: False, 76: False, 77: False, 78: False, 79: True, 80: False, 81: False, 82: False, 83: True, 84: False, 85: False, 86: False, 87: False, 88: False, 89: True, 90: False, 91: False, 92: False, 93: False, 94: False, 95: False, 96: False, 97: True, 98: False, 99: False}
Help on module isprime:

NAME
    isprime

DESCRIPTION
    isprime:
      Determine if a given number is prime
    Usage:
      import isprime
      
      isprime.isprime(42)
      
        OR
    
      from isprime import isprime
      
      isprime(4423)

FUNCTIONS
    isprime(x: int) -> bool
        >>> isprime(2)
        True
        >>> isprime(10)
        False

FILE
    /workspace/isprime.py
help()関数にモジュールを渡すと __docstring__ がレンダリングされます。

例外処理(れいがいしょり、exception handling)とは、プログラム実行中に予期せぬ異常が発生した場合に、通常の実行フローを中断し、エラーメッセージの表示や適切な処理を行うプログラムの手法です。

raise

[編集]

raise文は、プログラムの実行中に発生したエラーや問題を示し、その場で例外を引き起こします。例えば、条件に合致しない場合や予期せぬ状況であれば、raise文を使って例外を発生させることができます。

def reduce(array, callback, initialValue):
    if not callable(callback):
        raise ValueError(str(callback) + " is not a function")
    # ...

reduce([], None, None)
実行結果
Traceback (most recent call last):
  File "Main.py", line 6, in <module>
    reduce([], None, None) 
  File "Main.py", line 3, in reduce
    raise ValueError(str(callback) + " is not a function") 
ValueError: None is not a function

後述のtry/except ブロックなしで raise を実行すると、エラーが現在のコンテキストから伝播し、エラーが発生したポイントからコードの実行が停止されます。これにより、通常の実行フローが中断され、エラーがコンソールに表示されたり、上位の呼び出し元でエラーがキャッチされるまで、エラーが伝播します。

try節とexcept節

[編集]

tryexceptは、Pythonにおける例外処理を行うための構文です。tryブロック内のコードを実行し、もし例外が発生した場合に備えてそれをキャッチするためのものです。

基本的な構文は以下のようになります。

try:
    # ここに例外が発生する可能性のあるコードを記述する
    # 例外が発生した場合、次の行からの実行は中断される
    # 例外が発生しなければ、exceptブロックは実行されない
except エラーの種類 as エラーオブジェクト:
    # 例外が発生した場合に行う処理を記述する
    # エラーの種類に応じて処理を変えることができる
finally:
    # 必要に応じて、例外の発生に関わらず最後に実行される処理を記述する

例外が発生する可能性があるコードをtryブロックに記述し、もし例外が発生した場合、その種類に応じたexceptブロックが実行されます。exceptブロックでは例外の種類を指定し、その例外が発生した際に実行するコードを記述します。

例えば:

try:
    result = 10 / 0  # ゼロ除算の例外が発生する可能性があるコード
except ZeroDivisionError as e:
    print("エラーが発生しました:", e)

この例では、ゼロ除算の例外が発生する可能性があるため、tryブロックで計算を行っています。もしゼロ除算のエラーが発生すれば、exceptブロックが実行され、エラーメッセージが表示されます。

else節とfinally節

[編集]

Pythonの例外処理には、tryexceptに加えてelse節とfinally節もあります。else節は、tryブロック内で例外が発生しなかった場合に実行される部分です。

基本的な構文は次のようになります:

try:
    # 例外が発生する可能性のあるコード
except エラーの種類 as エラーオブジェクト:
    # 例外が発生した場合の処理
else:
    # 例外が発生しなかった場合の処理
finally:
    # 例外の有無に関わらず最後に実行される処理

else節は、tryブロック内で例外が発生せず、正常に処理が完了した場合に実行されます。例外が発生した場合はexceptブロックが実行され、例外が発生しなかった場合はelseブロックが実行されるという流れです。

例えば:

try:
    result = 10 / 2  # 例外が発生しないようなコード
except ZeroDivisionError as e:
    print("ゼロ除算エラー:", e)
else:
    print("計算結果:", result)
finally:
    print("処理が完了しました")

この例では、tryブロック内でゼロ除算が行われていないため、exceptブロックは実行されず、代わりにelseブロックが実行され、計算結果が表示されます。最後にfinallyブロックが実行され、"処理が完了しました"というメッセージが表示されます。

return と finally

[編集]
return と finally
def div(n, d) :
    try :
        return n / d
    except Exception as e:
        print(e)
    finally :
        print("div(%s, %s) -- finally" % (n, d))

print("div(1, 2) = %s" % div(1, 2))
print("div(1, 0) = %s" % div(1, 0))
print("div(0, 0) = %s" % div(0, 0))
実行結果
div(1, 2) -- finally
div(1, 2) = 0.5
division by zero
div(1, 0) -- finally
div(1, 0) = None
division by zero
div(0, 0) -- finally
div(0, 0) = None
try文にfinally節を持つ言語では「tryブロックで例外を出さずのreturn文に達したとき、finally節を実行するか?」が問題になります。
Puthonでは、return文に達してもfinally節が実行されます。

例外の場合わけ

[編集]

Pythonにおける例外の場合分けは、tryexceptを使用して行います。exceptブロックは、特定の例外が発生した場合にそれをキャッチして処理するために使用されます。また、exceptブロックは複数指定することもできます。

例えば:

try:
    result = 10 / 0  # 例外が発生する可能性のあるコード
except ZeroDivisionError as e:
    print("ゼロ除算エラー:", e)
except TypeError as e:
    print("型エラーが発生しました:", e)
except Exception as e:
    print("予期せぬエラーが発生しました:", e)

上記の例では、tryブロック内でゼロ除算が行われています。しかし、ZeroDivisionError以外のエラーが発生する可能性もあるため、複数のexceptブロックで異なる例外をキャッチするようにしています。exceptブロックの最後にExceptionを指定することで、すべての予期せぬ例外をキャッチすることができます。

また、exceptブロックで例外をキャッチするだけでなく、例外の情報を取得したり、適切な処理を行ったりすることもできます。

try:
    num = int(input("数字を入力してください: "))
    result = 10 / num
    print("計算結果:", result)
except ValueError:
    print("無効な値が入力されました。整数を入力してください。")
except ZeroDivisionError:
    print("ゼロで除算することはできません。")
else:
    print("正常に計算が完了しました。")
finally:
    print("プログラムの実行が終了しました。")

この例では、ユーザーから整数の入力を受け取り、その入力に応じて計算を行います。ValueErrorZeroDivisionErrorなどの特定の例外に応じてメッセージを表示し、それぞれの状況に適した対処を行っています。elseブロックは例外が発生しなかった場合に実行され、finallyブロックは最後に必ず実行されます。

組込み例外一覧

[編集]

__builtins__ の要素のうち BaseExceptionのサブクラスを例外とし、例外と例外の __doc__ を表にしました。

組込み例外一覧
#print(issubclass(ValueError, Exception))
ex = []
for k in vars(__builtins__):
    try:
        if eval(f"issubclass({k}, BaseException)"):
            ex.append(k)
    except TypeError:
        pass

print(f"""\
{{| class=wikitable
|+ 組込み例外
!例外!!__doc__\
""")

for k in sorted(ex):
    print(f"""\
|-
! {k}
| {eval(f"{k}.__doc__")}\
""")

print("|}")

このコードは、Pythonの__builtins__モジュール内の組み込み例外クラスを取得しています。具体的には、BaseExceptionクラスを継承している例外クラスを収集してリストに追加しています。

以下、このコードの動作を詳しく説明します。

  1. __builtins__モジュールにはPythonの組み込み関数や組み込み例外が含まれています。
  2. vars(__builtins__)を使うことで、__builtins__モジュール内の変数(関数やクラスなど)の辞書を取得できます。
  3. ループを使ってvars(__builtins__)内の各要素(k)に対して処理を行います。
  4. issubclass()関数は、1つのクラスが別のクラスのサブクラスであるかどうかを確認します。
  5. eval()関数を使って文字列をPythonコードとして評価し、issubclass()を使ってBaseExceptionクラスを継承しているかどうかを確認します。
  6. BaseExceptionクラスを継承している場合、その例外クラス名をリストexに追加します。
  7. tryブロック内でTypeErrorが発生した場合(例外クラスがissubclass()に適合しない場合)、exceptブロックでpassを使って何もせずにスキップします。

つまり、このコードは組み込みの例外クラスを調べ、BaseExceptionクラスを継承しているものをリストexに追加するものです。例外ハンドリングや特定の例外クラスに対する処理を行う際に、組み込みの例外クラスを動的に取得する際に役立ちます。

組込み例外
例外 __doc__
ArithmeticError Base class for arithmetic errors.
AssertionError Assertion failed.
AttributeError Attribute not found.
BaseException Common base class for all exceptions
BlockingIOError I/O operation would block.
BrokenPipeError Broken pipe.
BufferError Buffer error.
BytesWarning Base class for warnings about bytes and buffer related problems, mostly

related to conversion from str or comparing to str.

ChildProcessError Child process error.
ConnectionAbortedError Connection aborted.
ConnectionError Connection error.
ConnectionRefusedError Connection refused.
ConnectionResetError Connection reset.
DeprecationWarning Base class for warnings about deprecated features.
EOFError Read beyond end of file.
EnvironmentError Base class for I/O related errors.
Exception Common base class for all non-exit exceptions.
FileExistsError File already exists.
FileNotFoundError File not found.
FloatingPointError Floating point operation failed.
FutureWarning Base class for warnings about constructs that will change semantically

in the future.

GeneratorExit Request that a generator exit.
IOError Base class for I/O related errors.
ImportError Import can't find module, or can't find name in module.
ImportWarning Base class for warnings about probable mistakes in module imports
IndentationError Improper indentation.
IndexError Sequence index out of range.
InterruptedError Interrupted by signal.
IsADirectoryError Operation doesn't work on directories.
KeyError Mapping key not found.
KeyboardInterrupt Program interrupted by user.
LookupError Base class for lookup errors.
MemoryError Out of memory.
ModuleNotFoundError Module not found.
NameError Name not found globally.
NotADirectoryError Operation only works on directories.
NotImplementedError Method or function hasn't been implemented yet.
OSError Base class for I/O related errors.
OverflowError Result too large to be represented.
PendingDeprecationWarning Base class for warnings about features which will be deprecated

in the future.

PermissionError Not enough permissions.
ProcessLookupError Process not found.
RecursionError Recursion limit exceeded.
ReferenceError Weak ref proxy used after referent went away.
ResourceWarning Base class for warnings about resource usage.
RuntimeError Unspecified run-time error.
RuntimeWarning Base class for warnings about dubious runtime behavior.
StopAsyncIteration Signal the end from iterator.__anext__().
StopIteration Signal the end from iterator.__next__().
SyntaxError Invalid syntax.
SyntaxWarning Base class for warnings about dubious syntax.
SystemError Internal error in the Python interpreter.

Please report this to the Python maintainer, along with the traceback, the Python version, and the hardware/OS platform and version.

SystemExit Request to exit from the interpreter.
TabError Improper mixture of spaces and tabs.
TimeoutError Timeout expired.
TypeError Inappropriate argument type.
UnboundLocalError Local name referenced but not bound to a value.
UnicodeDecodeError Unicode decoding error.
UnicodeEncodeError Unicode encoding error.
UnicodeError Unicode related error.
UnicodeTranslateError Unicode translation error.
UnicodeWarning Base class for warnings about Unicode related problems, mostly

related to conversion problems.

UserWarning Base class for warnings generated by user code.
ValueError Inappropriate argument value (of correct type).
Warning Base class for warning categories.
ZeroDivisionError Second argument to a division or modulo operation was zero.

Pythonのクラスについて学ぶことで、自分自身のデータ型を定義して、その型に基づいて作成されたオブジェクトにアクセスする方法を学ぶことができます。 このチュートリアルでは、Pythonでクラスを定義する方法、クラスオブジェクトとインスタンスオブジェクトの違い、クラス変数とインスタンス変数、メソッド、継承、プライベート変数とメソッド、プロパティ、抽象基底クラスなどのトピックについて説明します。


クラスの概要

[編集]

Pythonのクラスは、オブジェクト指向プログラミングにおける基本的な概念の一つで、データと関数をまとめて扱うことができます。

クラスは、プログラム内でオブジェクトを作成するための設計図のようなものです。クラスには、そのオブジェクトが持つ属性(データ)や振る舞い(メソッド)が定義されています。クラスを定義することで、同じような性質を持ったオブジェクトを簡単に作成することができます。

クラスの中で定義されたデータは、クラス変数とインスタンス変数の2種類があります。クラス変数は、そのクラスが持つデータであり、全てのインスタンスで共有されます。インスタンス変数は、オブジェクトごとに異なる値を持つデータであり、各インスタンスごとに独立しています。

メソッドは、オブジェクトの振る舞いを定義するための関数です。クラスに定義されたメソッドは、インスタンスを通じて呼び出すことができます。

クラスは、継承を使って他のクラスを拡張することができます。継承することで、既存のクラスの機能を再利用し、新たな機能を追加することができます。

また、Pythonにはプライベート変数やプロパティ、抽象基底クラスなど、クラスをより強力にするための機能があります。これらの機能を使うことで、より柔軟で安全なコードを書くことができます。

クラスの定義方法

[編集]

Pythonでは class キーワードを使用してクラスを定義します。基本的な構文は以下の通りです。

class ClassName:
    # クラスの本体

クラス名は、PascalCase で書かれた単語である必要があります。クラスの本体には、変数や関数を定義することができます。

クラスを定義する

[編集]

以下の例では、Person というクラスを定義しています。このクラスには、名前と年齢のインスタンス変数、およびそれらを設定するための __init__ メソッドが含まれています。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

このクラスを使うと、以下のようにして Person のインスタンスを作成することができます。

person1 = Person("Alice", 25)
person2 = Person("Bob", 30)

クラスオブジェクトとインスタンスオブジェクト

[編集]

クラス定義によって作成されたオブジェクトには、2つの種類があります。1つはクラスオブジェクトであり、もう1つはインスタンスオブジェクトです。

クラスオブジェクト

[編集]

クラスオブジェクトは、クラス定義に基づいて作成され、クラス変数にアクセスするために使用されます。

class MyClass:
    class_variable = 0

print(MyClass.class_variable)

この場合は、MyClass がクラスオブジェクトです。

インスタンスオブジェクト

[編集]

インスタンスオブジェクトは、クラスから作成された各オブジェクトのことを指します。それぞれのインスタンスは、独自の状態を保持できます。

class MyClass:
    def __init__(self):
        self.instance_variable = 0

my_object1 = MyClass()
my_object2 = MyClass()
print(my_object1.instance_variable)
print(my_object2.instance_variable)

この場合は、my_object1my_object2 がインスタンスオブジェクトです。

曖昧さのない場合は、クラスオブジェクトをクラス、インスタンスオブジェクトをインスタンスと呼びます。

クラス変数とインスタンス変数

[編集]

クラス変数はクラス内で定義され、すべてのインスタンスで共有される変数です。インスタンス変数は、各インスタンスごとに異なる値を持つ変数です。

クラス変数とインスタンス変数の定義

[編集]

以下は、クラス変数とインスタンス変数を定義する例です。

class MyClass:
    class_variable = 0  # クラス変数

    def __init__(self, instance_variable):
        self.instance_variable = instance_variable  # インスタンス変数

上記の例では、class_variableはクラス変数、instance_variableはインスタンス変数です。class_variableはクラス内で定義され、インスタンス作成前に定義されます。instance_variableは、__init__メソッド内で初期化されるため、インスタンスが作成されるたびに異なる値が割り当てられます。

クラス変数とインスタンス変数のアクセス方法

[編集]

以下は、クラス変数とインスタンス変数をアクセスする例です。

class MyClass:
    class_variable = 0  # クラス変数

    def __init__(self, instance_variable):
        self.instance_variable = instance_variable  # インスタンス変数

my_instance = MyClass(1)
print(my_instance.class_variable)  # クラス変数のアクセス方法
print(my_instance.instance_variable)  # インスタンス変数のアクセス方法

MyClass.class_variable = 2  # クラス変数の変更
my_other_instance = MyClass(3)
print(my_other_instance.class_variable)  # クラス変数の変更後のアクセス方法

上記の例では、my_instanceMyClassのインスタンスであり、class_variableinstance_variableにアクセスしています。MyClass.class_variableを変更すると、MyClassのすべてのインスタンスが新しい値を持つようになります。

メソッド

[編集]

Pythonにおけるメソッドとは、オブジェクトが持つ関数のことです。メソッドは、クラス内に定義された関数であり、オブジェクトに対して呼び出されることが前提となっています。 メソッドは、インスタンスメソッド、クラスメソッド、スタティックメソッド、特殊メソッドなど、種類によって様々な特徴を持っています。 インスタンスメソッドは、そのオブジェクトに対して呼び出され、クラスメソッドは、そのクラスに対して呼び出されます。 スタティックメソッドは、オブジェクトやクラスに関係なく、独立して呼び出されます。 特殊メソッドは、Pythonが提供する特別な機能を持つメソッドであり、例えば、__init____str__などがあります。

インスタンスメソッド

[編集]

インスタンスメソッドは、クラスのインスタンスによって呼び出されます。第1引数は必ず self で、それを使ってインスタンスの属性にアクセスできます。

class MyClass:
    def instance_method(self, arg1, arg2):
        self.arg1 = arg1
        self.arg2 = arg2
        print(f"Called instance_method with {self.arg1} and {self.arg2}")

obj = MyClass()
obj.instance_method("hello", "world")  # "Called instance_method with hello and world"

このコードは、インスタンスメソッドの例です。 instance_methodは、selfを最初の引数として受け取り、その引数はメソッドが呼び出されたインスタンス自体を指します。このインスタンスを介して、メソッドはオブジェクトの状態を変更することができます。引数arg1arg2は、メソッドに渡され、メソッドの処理に使用されます。

上記のコードは、MyClassのインスタンスobjを作成し、instance_methodを呼び出しています。 instance_methodは、 objがインスタンスであるため、selfとして自分自身を参照し、 "Called instance_method with hello and world"という文字列を出力します。

単にメソッドと言った場合、インスタンスメソッドを示すことが多いですが、文脈に注意しましょう。

クラスメソッド

[編集]

クラスメソッドは、クラス自体によって呼び出されます。第1引数は必ず cls で、それを使ってクラスの属性にアクセスできます。

class MyClass:
    class_var = "class variable"
    
    @classmethod
    def class_method(cls, arg):
        cls.arg = arg
        print(f"Called class_method with {cls.arg} and {cls.class_var}")

MyClass.class_method("hello")  # "Called class_method with hello and class variable"

上記のコードは、MyClass というクラスを定義し、その中に class_var というクラス変数を定義し、class_method というクラスメソッドを定義しています。

class_method は、@classmethod デコレータで修飾されており、第一引数が cls というクラスオブジェクトであることが示されています。クラスメソッドは、クラス自身を第一引数として受け取るため、クラス変数にアクセスしたい場合は、cls.class_var のようにしてアクセスすることができます。

このクラスメソッドは、arg という引数を受け取り、cls.arg にその値を代入し、cls.argcls.class_var を用いてメッセージを出力するという動作をします。

最後の行では、class_method をクラス名で呼び出しています。class_method がクラスメソッドであるため、第一引数にはクラスオブジェクト MyClass が自動的に渡されます。

スタティックメソッド

[編集]

スタティックメソッドは、クラス自体やインスタンスから呼び出すことができます。スタティックメソッドは selfcls が必要ないため、第1引数を定義しません。

class MyClass:
    @staticmethod
    def static_method(arg):
        print(f"Called static_method with {arg}")

MyClass.static_method("hello")  # "Called static_method with hello"

この例では、@staticmethod デコレータが使われています。このデコレータを使うことで、メソッドがスタティックメソッドであることを明示的に示すことができます。

スタティックメソッドはクラスに属していますが、インスタンスには属していないため、引数に selfcls を必要としません。そのため、スタティックメソッドは通常、インスタンス変数を使用する必要がない場合に使用されます。

上記の例では、@staticmethod を使って static_method メソッドを定義しています。このメソッドは arg という引数を受け取り、"Called static_method with {arg}" というメッセージを出力します。

最後の行では、MyClass.static_method("hello") というコードを実行することで、static_method メソッドを呼び出しています。この結果、"Called static_method with hello" というメッセージが出力されます。

特殊メソッド

[編集]

特殊メソッドは、Pythonによって予約されたメソッドで、オブジェクトの様々な振る舞いを定義することができます。特殊メソッドは、名前が __ で始まり、終わります。

例えば、__init__() は、オブジェクトが作成されるときに自動的に呼び出されるメソッドで、インスタンス変数の初期化などの処理を行います。

class MyClass:
    def __init__(self, arg1, arg2):
        self.arg1 = arg1
        self.arg2 = arg2
        print(f"Called __init__ with {self.arg1} and {self.arg2}")

obj = MyClass("hello", "world")  # "Called __init__ with hello and world"

このコードは、MyClassという名前のクラスを定義し、__init__という特殊メソッドを使ってインスタンスを初期化しています。 __init__メソッドは、クラスがインスタンス化される際に自動的に呼び出されます。このメソッドは、インスタンスの属性を初期化するのに使用されます。 上記の例では、MyClassのインスタンスを作成し、"hello"という値をarg1に、"world"という値をarg2に割り当て、__init__メソッドが呼び出されたことを示す出力が表示されます。

例えば、__add__メソッドを定義すると、+演算子をオーバーロードして、クラスのインスタンス同士を加算できるようになります。

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y)
    
    def __str__(self):
        return f"Point({self.x}, {self.y})"

# 使用例
p1 = Point(1, 2)
p2 = Point(3, 4)
result = p1 + p2
print(result)  # Point(4, 6)

上記の例では、Pointクラスに__add__メソッドを定義して、2つのPointインスタンスを加算できるようにしています。__str__メソッドはオブジェクトを文字列に変換する際に呼ばれる特殊メソッドであり、ここではprint関数を使ってPointオブジェクトを出力する際に使用されています。

他にも、__sub__(減算)、__mul__(乗算)、__eq__(等価)、__lt__(小なり)など、さまざまな特殊メソッドがあります。これらを使うことで、クラスのインスタンスが自然な方法で演算子を扱えるようにすることができます。

は代表的な特殊メソッド
メソッド名 説明
__init__(self[, ...]) インスタンスが作成されるときに呼び出される。初期化のためのメソッドで、必須の引数は self 以外にある。
__str__(self) str() 関数で呼び出される。オブジェクトを表す文字列を返す。
__repr__(self) repr() 関数で呼び出される。オブジェクトを表す公式的な文字列を返す。
__len__(self) len() 関数で呼び出される。オブジェクトの長さを返す。
__getitem__(self, key) インデックスを使用して要素を取得するために [] 演算子で呼び出される。
__setitem__(self, key, value) インデックスを使用して要素を設定するために [] 演算子で呼び出される。
__delitem__(self, key) インデックスを使用して要素を削除するために [] 演算子で呼び出される。
__contains__(self, item) in 演算子で呼び出される。オブジェクトが指定された要素を含む場合に True を返す。
__call__(self[, args...]) オブジェクトが関数として呼び出されたときに呼び出される。
Pythonのクラスのインスタンスにforを適用する
Pythonのクラスのインスタンスに for 文を適用するには、クラスに __iter__()__next__() メソッドを実装する必要があります。これらのメソッドを実装することで、クラスのインスタンスをイテレータとして扱うことができます。
  • __iter__() メソッドは、イテレータ自身を返す必要があります。通常は、クラスのインスタンス自身を返します。
  • __next__() メソッドは、次の要素を返します。もう要素がない場合は、StopIteration を発生させます。

以下は、クラスのインスタンスに for 文を適用する例です。

class MyIterator:
    def __init__(self, items):
        self.items = items
        self.current = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.current < len(self.items):
            item = self.items[self.current]
            self.current += 1
            return item
        else:
            raise StopIteration

my_iter = MyIterator([2, 3, 5])

for item in my_iter:
    print(item)
# 2
# 3
# 5

上記の例では、MyIterator というクラスを定義し、__iter__()__next__() メソッドを実装しています。

MyIterator クラスのインスタンスを for 文でループさせることができます。

継承

[編集]

継承とは、既存のクラスを基に新しいクラスを作り出すことで、既存のクラスの機能を引き継ぎながら、新たな機能を追加することができます。

スーパークラスの定義

[編集]

スーパークラスは、継承元のクラスのことを指します。スーパークラスの定義は、通常のクラス定義と同じように行います。

以下の例では、Person というクラスをスーパークラスとして定義しています。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def say_hello(self):
        print(f"My name is {self.name} and I am {self.age} years old.")

このスーパークラス Person は、nameage の属性を持ち、say_hello() メソッドを定義しています。

サブクラスの定義

[編集]

サブクラスは、スーパークラスを継承して新たなクラスを作り出すことができます。サブクラスは、新たに追加する属性やメソッドを定義することができます。

以下の例では、Student というクラスを、スーパークラスである Person を継承して定義しています。

class Student(Person):
    def __init__(self, name, age, grade):
        super().__init__(name, age)
        self.grade = grade
        
    def say_hello(self):
        print(f"My name is {self.name}, I am {self.age} years old and my grade is {self.grade}.")

このサブクラス Student は、Person クラスを継承して、grade の属性を追加し、say_hello() メソッドをオーバーライドしています。

オーバーライド

[編集]

サブクラスでスーパークラスのメソッドを再定義することをオーバーライドと呼びます。サブクラスで同名のメソッドを定義することで、スーパークラスのメソッドを上書きすることができます。

上記の例では、Student クラスで say_hello() メソッドを再定義し、出力内容を変更しています。

super() 関数

[編集]

サブクラスでスーパークラスのメソッドを呼び出すには、super() 関数を使用します。super() 関数を呼び出すことで、スーパークラスのメソッドを呼び出すことができます。

上記の例では、Student クラスの __init__() メソッドで、super() 関数を使用して、スーパークラスの __init__() メソッドを呼び出しています。 これにより、Person クラスで定義した name と age の属性を、Student クラスでも使用することができます。

多重継承

[編集]

Python では、複数のクラスを同時に継承することができます。これを多重継承と呼びます。多重継承では、カンマで区切って複数のスーパークラスを指定します。 以下の例では、Person クラスというスーパークラスを継承し、さらに、Swimmer というクラスも同時に継承しています。

class Swimmer:
    def swim(self):
        print("I'm swimming!")

class SwimmingStudent(Person, Swimmer):
    def __init__(self, name, age, grade):
        super().__init__(name, age)
        self.grade = grade

    def say_hello(self):
        print(f"My name is {self.name}, I am {self.age} years old and my grade is {self.grade}.")
    
    def swim(self):
        print("I'm swimming like a pro!")
    
SwimmingStudent("Alice", 10, 5).swim() # => I'm swimming like a pro!

上記の例では、Swimmer クラスを定義して、swim() メソッドを持たせています。 そして、SwimmingStudent クラスで Person クラスと Swimmer クラスの両方を継承しています。 さらに、SwimmingStudent クラスで swim() メソッドをオーバーライドして、Swimmer クラスで定義した swim() メソッドと異なる動作をするようにしています。 最後に、SwimmingStudent クラスのインスタンスを作成して、swim() メソッドを呼び出した結果、Swimmer クラスで定義した swim() メソッドではなく、SwimmingStudent クラスでオーバーライドした swim() メソッドが呼び出されることが確認できます。

継承されることを想定した標準モジュールのクラス
Pythonの標準モジュールの中で、継承を想定して設計されたクラスとしては、以下のようなものがあります。
  1. collections.abc モジュール
    • Iterable: イテレーション可能なオブジェクトを定義する抽象基底クラス
    • Container: 要素の有無を調べることができるオブジェクトを定義する抽象基底クラス
    • Sized: 要素の数を返す len() 関数を実装することができるオブジェクトを定義する抽象基底クラス
    • Callable: 呼び出し可能オブジェクトを定義する抽象基底クラス
    • Hashable: ハッシュ可能なオブジェクトを定義する抽象基底クラス
    • Mapping: キーと値の対応を表す辞書型オブジェクトを定義する抽象基底クラス
    • MutableMapping: キーと値の対応を表す辞書型オブジェクトを変更することができる抽象基底クラス
    • Sequence: インデックスを用いて要素にアクセスできるオブジェクトを定義する抽象基底クラス
    • MutableSequence: インデックスを用いて要素にアクセスし、変更することができるオブジェクトを定義する抽象基底クラス
  2. enum モジュール
    • Enum: 列挙型オブジェクトを定義する基底クラス
  3. abc モジュール
    • ABC: 抽象基底クラスを定義する基底クラス
    • abstractmethod: 抽象メソッドを定義するためのデコレータ
  4. typing モジュール
    • Type: クラスオブジェクトを表す型を定義するクラス
    • TypeVar: 型変数を定義するクラス
    • Generic: ジェネリッククラスを定義する基底クラス
    • Protocol: プロトコルを定義する基底クラス
これらのクラスは、Pythonの標準ライブラリで広く使われており、継承によってカスタマイズされたクラスを作成することができます。また、これらのクラスを継承することで、多態性の実現や、型ヒントによる静的解析などの恩恵を受けることができます。

プライベート変数とメソッド

[編集]

プライベート変数やメソッドとは、クラスの外から直接アクセスできないようにするために用意されたものです。Pythonでは、アンダースコア(_)で始まる変数名やメソッド名を定義することで、プライベート変数やメソッドを作成することができます。

プライベート変数とメソッドの定義方法

[編集]

プライベート変数を定義する場合、変数名の先頭にアンダースコアを付けます。以下の例では、Person クラスにプライベート変数 _password を定義しています。

class Person:
    def __init__(self, name, age, password):
        self.name = name
        self.age = age
        self._password = password
        
    def say_hello(self):
        print(f"My name is {self.name} and I am {self.age} years old.")
        
    def _show_password(self):
        print(f"My password is {self._password}.")

同様に、プライベートメソッドを定義する場合も、メソッド名の先頭にアンダースコアを付けます。上記の例では、Person クラスにプライベートメソッド _show_password() を定義しています。

プライベート変数とメソッドのアクセス方法

[編集]

プライベート変数やメソッドは、クラスの外から直接アクセスすることができません。しかし、アクセスする方法が用意されています。

プライベート変数にアクセスする場合、変数名の前にアンダースコアを付けます。以下の例では、Person クラスのインスタンス p から、プライベート変数 _password にアクセスしています。

p = Person("Alice", 25, "password123")
print(p._password) # "password123" を出力

ただし、この方法は推奨されていません。Pythonでは、アンダースコアで始まる変数やメソッドは、外部から直接アクセスしないことが慣例となっています。プライベート変数やメソッドにアクセスする場合は、公開されているインターフェースを通じて行うようにしましょう。

プライベートメソッドにアクセスする場合、同様にメソッド名の前にアンダースコアを付けます。以下の例では、Person クラスのインスタンス p から、プライベートメソッートメソッド _show_password() にアクセスしています。

p = Person("Alice", 25, "password123")
p._show_password() # "My password is password123." を出力

同様に、クラス内で定義された公開メソッドを通じて、プライベート変数やメソッドにアクセスすることもできます。

以下の例では、Person クラスに公開メソッド get_password() を定義し、それを通じてプライベート変数 _password にアクセスしています。

class Person:
    def __init__(self, name, age, password):
        self.name = name
        self.age = age
        self._password = password

    def say_hello(self):
        print(f"My name is {self.name} and I am {self.age} years old.")
    
    def _show_password(self):
        print(f"My password is {self._password}.")
    
    def get_password(self):
        return self._password

p = Person("Alice", 25, "password123")
print(p.get_password()) # "password123" を出力

このように、Pythonでは、プライベート変数やメソッドを定義することで、クラスの外からの直接アクセスを制限することができます。 ただし、アクセスするための手段は用意されているため、必要な場合には適切に利用するようにしましょう。

プロパティ

[編集]

プロパティとは、クラスの外からもアクセスできるようにしたい変数を指します。 しかし、変数に直接アクセスすると不適切な値が設定される可能性があるため、アクセス時に特定の処理を実行する必要があります。 このような場合に、プロパティを使います。

プロパティの定義方法

[編集]

Pythonでは、プロパティを定義するには property ビルトイン関数を使用します。プロパティを定義するには、以下のような方法があります。

getter関数のみを定義する場合

[編集]

getter関数のみを定義する場合、以下のように @property デコレータを使用して、getter関数にアクセスすることができます。

class Person:
    def __init__(self, name, age):
        self._name = name
        self._age = age

    @property
    def name(self):
        return self._name

    @property
    def age(self):
        return self._age

このように定義することで、インスタンスから以下のようにして nameage にアクセスすることができます。

person = Person("Alice", 25)
print(person.name) # "Alice" を出力
print(person.age) # 25 を出力

getter関数とsetter関数の両方を定義する場合

[編集]

getter関数とsetter関数の両方を定義する場合、以下のように @property デコレータと @<property名>.setter デコレータを使用して、getter関数とsetter関数にアクセスすることができます。

class Person:
    def __init__(self, name, age):
        self._name = name
        self._age = age

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, value):
        self._age = value

このように定義することで、インスタンスから以下のようにして nameage にアクセスし、変更することができます。

person = Person("Alice", 25)
print(person.name) # "Alice" を出力
print(person.age) # 25 を出力

person.name = "Bob"
person.age = 30

print(person.name) # "Bob" を出力
print(person.age) # 30 を出力

プロパティのアクセス方法

[編集]

プロパティにアクセスする場合、通常のインスタンス変数と同様に、以下のようにしてアクセスします。

person = Person("Alice", 25)
print(person.name) # "Alice" を出力
print(person.age) # 25 を出力

また、setter関数を定義している場合、以下のようにしてプロパティの値を変更することができます。

person.name = "Bob"
person.age = 30

print(person.name) # "Bob" を出力
print(person.age) # 30 を出力

プロパティを使用することで、クラスの外部からもインスタンス変数にアクセスできるようになり、getter関数やsetter関数を使用することで、変数の値に対して特定の処理を行うことができます。 これにより、クラスのカプセル化が実現され、安全で信頼性の高いコードを作成することができます。

__getattr__ と __setattr__

[編集]

__getattr____setattr__ は Python の特殊メソッドで、オブジェクトの属性に対するアクセスをカスタマイズすることができます。

__getattr__ メソッドは、インスタンスの属性が未定義の場合に呼び出されます。通常の属性アクセスが失敗した場合に呼び出され、属性名を引数に取り、属性の値を返すように実装することができます。このメソッドを使用することで、動的な属性アクセスをサポートすることができます。

例えば、以下のようなクラス DynamicObject を考えます。

class DynamicObject:
    def __getattr__(self, name):
        return f"{name} is not defined."

このクラスは、未定義の属性にアクセスした場合に、属性名と "is not defined." の文字列を連結したものを返します。

obj = DynamicObject()
print(obj.foo)
# 出力: foo is not defined.

一方、__setattr__ メソッドは、属性に値を代入する際に呼び出されます。通常の属性代入が行われた後に、属性名と代入された値を引数に取り、任意の処理を実行することができます。このメソッドを使用することで、属性代入時のチェックや変換処理を実装することができます。

例えば、以下のようなクラス PositiveNumber を考えます。

class PositiveNumber:
    def __init__(self, value):
        self.value = value

    def __setattr__(self, name, value):
        if value < 0:
            raise ValueError("Value must be positive.")
        super().__setattr__(name, value)

このクラスは、属性に代入される値が負数である場合に、 ValueError を発生させます。

n = PositiveNumber(1)
n.value = 2
print(n.value)
# 出力: 2

n.value = -1
# ValueError: Value must be positive.
注意点
__getattr__ メソッドや __setattr__ メソッドは、インスタンスの属性アクセスや属性代入時にのみ呼び出されます。
クラス自体にアクセスする場合には、 __getattr__ メソッドや __setattr__ メソッドは呼び出されません。
属性が存在する場合は __getattr__ メソッドは呼び出されず、通常の属性アクセスが行われます。

クラス変数とインスタンス変数のプライベート化

[編集]

Pythonでは、クラス変数とインスタンス変数をプライベート化することができます。プライベート変数は、クラスの外から直接アクセスすることができなくなり、情報の隠蔽や保護に役立ちます。

クラス変数とインスタンス変数のプライベート化

[編集]

クラス変数とインスタンス変数をプライベート化するには、変数名の前にアンダースコア2つ(__)をつけます。例えば、以下のように定義します。

class MyClass:
    __private_class_var = 10  # クラス変数のプライベート化

    def __init__(self):
        self.__private_instance_var = 20  # インスタンス変数のプライベート化

これにより、MyClass の外からは __private_class_var__private_instance_var に直接アクセスできなくなります。ただし、Pythonでは名前修飾という仕組みがあり、アンダースコア2つを付けることで、クラス外からアクセスできなくするだけで、実際にはアクセス可能な変数として存在します。

プライベート変数のアクセス方法

[編集]

プライベート変数にアクセスするためには、アンダースコア1つ(_)を変数名の前に付けることでアクセスできます。例えば、以下のようにします。

class MyClass:
    __private_class_var = 10  # クラス変数のプライベート化

    def __init__(self):
        self.__private_instance_var = 20  # インスタンス変数のプライベート化

    def get_private_class_var(self):
        return MyClass.__private_class_var  # アクセス方法

    def get_private_instance_var(self):
        return self.__private_instance_var  # アクセス方法

上記の例では、get_private_class_var() メソッドと get_private_instance_var() メソッドを定義し、それぞれでプライベート変数にアクセスする方法を示しています。

my_class = MyClass()
print(my_class.get_private_class_var())  # 10 を出力
print(my_class.get_private_instance_var())  # 20 を出力

プライベート変数はクラスの外からアクセスできないようになっていますが、名前修飾を使用することで、直接アクセスすることができます。 ただし、名前修飾を使うことでアクセスできるようになっているため、注意が必要です。 プライベート変数は、クラス内部でしか使用しない変数であることを明確にし、情報を保護するために使用することが望ましいです。

抽象基底クラス

[編集]

抽象基底クラスは、インスタンス化できない抽象的なクラスで、共通のインターフェースを定義することができます。 具体的な実装は、抽象基底クラスを継承したサブクラスで行います。 Pythonでは、抽象基底クラスを作成するために abc モジュールを使用します。

抽象基底クラスの定義方法

[編集]

抽象基底クラスを定義するには、abc.ABC クラスを継承する必要があります。また、抽象メソッドを定義するには @abstractmethod デコレータを使用します。

以下は、抽象基底クラスの定義例です。

import abc

class MyABC(abc.ABC):
    
    @abc.abstractmethod
    def do_something(self):
        pass

上記の例では、MyABC という抽象基底クラスを定義しています。このクラスには、do_something という抽象メソッドが定義されています。

抽象基底クラスを継承したクラスの定義方法

[編集]

抽象基底クラスを継承するサブクラスを定義する場合、@abstractmethod で定義されたメソッドを実装する必要があります。また、抽象基底クラスを継承することで、共通のインターフェースを持つことができます。

以下は、抽象基底クラスを継承したクラスの定義例です。

class MyClass(MyABC):

    def do_something(self):
        print("MyClassの処理を実行しました")

上記の例では、MyClass というクラスを定義し、MyABC を継承しています。MyABC に定義された do_something メソッドを実装し、処理を行っています。

以上が、Pythonでの抽象基底クラスの定義方法、抽象基底クラスを継承したクラスの定義方法です。 抽象基底クラスを使用することで、共通のインターフェースを持つクラスを実装し、コードの再利用性を高めることができます。

Pythonのクラスと型アノテーション
Pythonでは、型アノテーションを使用して関数やメソッドの引数や返り値の型を指定できますが、クラスの属性やメソッドの戻り値などでも型アノテーションを指定することができます。

例えば、以下のようにクラス定義時に属性に対して型アノテーションを指定することができます。

class MyClass:
    def __init__(self, value: int) -> None:
        self.value = value

    def add_value(self, x: int) -> int:
        return self.value + x

この例では、__init__メソッドの引数valueと、add_valueメソッドの引数x、そしてadd_valueメソッドの戻り値に対して、型アノテーションが指定されています。value属性は整数型を持ち、add_valueメソッドは整数型の引数を受け取り、整数型の戻り値を返すことを表しています。

また、クラス全体に対して型アノテーションを指定することもできます。例えば、以下のようにクラス定義の先頭で型アノテーションを指定することができます。

class MyClass:
    value: int

    def __init__(self, value: int) -> None:
        self.value = value

    def add_value(self, x: int) -> int:
        return self.value + x

この例では、クラス定義の先頭でvalue属性に対して整数型を指定しています。このように、クラス定義の先頭で型アノテーションを指定することで、クラス全体に対して型を指定することができます。

なお、Pythonの型アノテーションは実行時には無視されますが、型チェッカーやIDEの補完機能などで利用されます。また、Pythonの型アノテーションはオプションであるため、必ずしも指定する必要はありません。ただし、型アノテーションを指定することで、コードの読みやすさや保守性を向上させることができます。

Ruby からの移植

[編集]

Ruby#ユーザー定義クラスをPython3に移植しました。

Ruby からの移植
import math

class GeoCoord(object):
    def __init__(self, longitude, latitude):
        self.longitude, self.latitude = longitude, latitude

    def __str__(self):
        ew, ns = "東経", "北緯"
        long, lat = self.longitude, self.latitude
        if long < 0.0:
            ew = "西経"
            long = -long
        if lat < 0.0:
            ns = "南緯"
            lat = -lat
        return f"({ew}: {long}, {ns}: {lat})"

    def distance(self, other):
        i = math.pi / 180
        r = 6371.008
        return (
            math.acos(
                math.sin(self.latitude * i) * math.sin(other.latitude * i)
                + math.cos(self.latitude * i)
                * math.cos(other.latitude * i)
                * math.cos(self.longitude * i - other.longitude * i)
            )
            * r
        )

Sites = {
    "東京駅": [139.7673068, 35.6809591],
    "シドニー・オペラハウス": [151.215278, -33.856778],
    "グリニッジ天文台": [-0.0014, 51.4778],
}
for name in Sites:
    Sites[name] = GeoCoord(*Sites[name])

for name in Sites:
    print(f"{name}: {Sites[name]}")

keys, len = tuple(Sites.keys()), len(Sites)
for i in range(len):
    x, y = keys[i], keys[(i + 1) % len]
    print(f"{x} - {