構文シュガー: Python が甘くて Python っぽい理由
Python には糖衣構文と呼ばれる構文がいくつかあります。この糖衣は厳密には必要な構文ではありませんが、Python に読みやすく、初心者に優しく、強力な言語としての風味を与えます。このチュートリアルでは、Python で最もよく使用される糖衣構文の一部を学習します。
実際には、これらの構文のほとんどは、よく知られた Python の構成要素が多く含まれているため、すでに使用されています。読み進めていくと、Python が内部でどのように動作するのかがわかり、Python を効率的かつ安全に使用する方法がわかります。
このチュートリアルでは、次のことを学習します。
- 糖衣構文とは
- 糖衣構文が演算子にどのように適用されるか
- どのように代入式が糖衣構文であるか
for
ループ と内包表記 が糖衣構文である理由- 他の Python の構造体も構文糖衣である仕組み
このチュートリアルを最大限に活用するには、演算子、式、ループ、デコレータ、クラス、コンテキスト マネージャーなどを含む Python の基本を理解している必要があります。
シュガー構文
プログラミングにおける構文シュガーとは、コードを簡素化し、読みやすく、または簡潔にする構文の一部を指します。構文シュガーを使用すると、より明確で読みやすい方法で物事を表現できます。
これにより、 この言語は人間が使用するのにより使いやすくなります。物事をより明確に、より簡潔に、または一部の人が好む別のスタイルで表現できます。 (ソース)
ただし、糖衣構文は、別の、より複雑な構造を使用しても同じ結果が得られるため、実際には必要ない場合があります。
注: このチュートリアルは、Python の糖衣構文の解明に関する Brett Cannon の一連の投稿からわずかに影響を受けています。このシリーズでは、ブレットが糖衣構文の各部分を深く掘り下げています。このチュートリアルなどで説明されている構文構造について詳しく説明したい場合は、このシリーズをチェックしてください。
Python には、コード内で定期的に使用する糖衣構文が多数含まれています。これらの構文構造により、Python はより読みやすく、より速く記述でき、ユーザーフレンドリーになります。これらの糖衣構文とその重要性を理解すると、Python の内部動作をより深く理解できるようになります。
まれに、特定の構文シュガーの脱糖バージョンの方がニーズを満たすことができる場合があります。したがって、特定の糖の代替コードについて知ることは、身に付けておくと良いスキルとなります。
Python の演算子
ほとんどのプログラミング言語と同様、Python では演算子が広範囲に使用されます。算術演算子、代入演算子、拡張代入演算子、比較演算子、ブール演算子、メンバーシップ演算子など、いくつかのカテゴリの演算子があります。これらの演算子はすべて、Python の糖衣構文の一部です。これらの演算子を使用すると、式をすばやく読みやすい方法で作成できます。
注: Python 演算子について詳しく知りたい場合は、「Python の演算子と式」チュートリアルを参照してください。
たとえば、算術演算子を使用すると、数学の授業で学んだものとよく似ているため、簡単に書いたり読んだりできる数式を作成できます。
>>> 5 + 7
12
>>> 10 - 4
6
>>> 2 * 4
8
>>> 20 / 2
10
最初の例では、プラス演算子 (+
) を使用して 2 つの数値を加算します。 2 番目の例では、減算演算子 (-
) を使用して 2 つの数値を減算します。最後の 2 つの例では、乗算と除算を実行します。
Python は特別なメソッドを通じて算術演算子をサポートしています。簡単な要約は次のとおりです。
Operator | Operation | Method |
---|---|---|
+ |
Addition | .__add__() |
- |
Subtraction | .__sub__() |
* |
Multiplication | .__mul__() |
/ |
Division | .__truediv__() |
// |
Integer division | .__floordiv__() |
** |
Exponentiation | .__pow__() |
Python が特別なメソッドを通じて演算子をサポートするとはどういう意味ですか?これは、演算子を使用するたびに、Python が内部で対応する特別なメソッドを呼び出すことを意味します。
注: マジック メソッドまたはダンダー メソッドとも呼ばれる特別なメソッドの詳細については、「Python のマジック メソッド: クラスでのパワーの活用」を参照してください。
説明のために、適切な特別なメソッドを使用して、以前に作成した算術演算を表現する方法を次に示します。
>>> 5 + 7
12
>>> (5).__add__(7)
12
>>> 10 - 4
6
>>> (10).__sub__(4)
6
>>> 2 * 4
8
>>> (2).__mul__(4)
8
>>> 20 / 2
10
>>> (20).__truediv__(2)
10
これらの例では、まず演算子を使用して算術式を作成する通常の方法があり、次に対応する特別なメソッドを使用して同等の構造を作成します。
ご覧のとおり、特別なメソッド構造を使用すると、コードが読みにくくなり、理解しにくくなります。したがって、演算子を使用すると作業が楽になり、コードが読みやすくなります。これらは糖衣構文です。
拡張代入演算子について考えてみると、それが糖衣構文のさらに良い例であることがわかります。拡張された追加の例を次に示します。
>>> count = 0
>>> count += 1
>>> count
1
この例では、+=
記号は拡張加算演算子であり、既存の変数に値を加算できるようになります。この式は、次の式のショートカットです。
>>> count = 0
>>> count = count + 1
>>> count
1
結論から言えば、両方の式は同等です。ただし、+=
演算子を使用した式の方が早く記述できます。
注: numbers=[1, 2, 3]
のようなリストの場合、numbers =numbers + [4]
のようなものは新しいリストを作成します。 リスト
オブジェクト。一方、numbers += [4]
のようなものは、numbers
をその場で変更します。したがって、拡張演算子を同等の式に置き換えて、見た目は同じ結果が得られるとしても、可変オブジェクトでは内部動作が異なることを知っておく必要があります。
比較演算子に関しては、特別なメソッドに置き換えることもできることがわかります。
Operator | Operation | Method |
---|---|---|
< |
Less than | .__lt__() |
<= |
Less than or equal | .__le__() |
> |
Greater than | .__gt__() |
>= |
Greater than or equal | .__ge__() |
== |
Equality | .__eq__() |
!= |
Inequality | .__ne__() |
これらのメソッドを使用すると、通常の比較式と同様に機能する構成を作成できます。次の式とそれに相当するメソッド呼び出しの例を考えてみましょう。
>>> 2 < 1
False
>>> (2).__lt__(1)
False
>>> 3 <= 7
True
>>> (3).__le__(7)
True
>>> 5 > 3
True
>>> (5).__gt__(3)
True
>>> 3 >= 7
False
>>> (3).__ge__(7)
False
>>> 1 == 1
True
>>> (1).__eq__(1)
True
>>> 1 != 1
False
>>> (1).__ne__(1)
False
これらの例では、すべての比較演算子をメソッド呼び出しに置き換えることができるため、すべての比較演算子が構文上の糖衣であることを確認します。
また、メンバーシップ テストを実行するための in
演算子と not in
演算子もあります。メンバーシップ テストを使用すると、値が特定の値のコレクションに含まれるかどうかを確認できます。
>>> 5 in [1, 2, 3, 4, 5]
True
>>> 5 not in [1, 2, 3, 4, 5]
False
>>> 100 in [1, 2, 3, 4, 5]
False
>>> 100 not in [1, 2, 3, 4, 5]
True
5
が値のリストに含まれているため、in
は True
を返し、not in
は False
を返します。code>。同様に、100
はリストにないため、in
は False
を返し、not in
は True を返します。
。
注: メンバーシップ テストの詳細については、Python の「in」演算子と「not in」演算子: メンバーシップの確認チュートリアルを参照してください。
実際には、これらの演算子を .__contains__()
メソッドの呼び出しに置き換えることができます。
>>> [1, 2, 3, 4, 5].__contains__(5)
True
>>> not [1, 2, 3, 4, 5].__contains__(5)
False
>>> [1, 2, 3, 4, 5].__contains__(100)
False
>>> not [1, 2, 3, 4, 5].__contains__(100)
True
あるいは、ターゲット反復可能オブジェクト内の値を反復処理する関数にアルゴリズムを実装することもできます。
>>> def is_member(value, iterable):
... for current_value in iterable:
... if current_value == value:
... return True
... return False
...
>>> is_member(5, [1, 2, 3, 4, 5])
True
>>> not is_member(5, [1, 2, 3, 4, 5])
False
>>> is_member(100, [1, 2, 3, 4, 5])
False
>>> not is_member(100, [1, 2, 3, 4, 5])
True
この例では、 is_member()
関数はターゲット値と反復可能値を引数として受け取ります。次に、ループを使用して値が反復可能内にあるかどうかを確認します。関数を呼び出した結果は、メンバーシップ演算子を使用した場合と同じになります。
連鎖した条件
場合によっては、2 つの比較を and
演算子で結合することがあります。たとえば、数値が指定された間隔内にあるかどうかを知りたいとします。この状況では、次のようなことができます。
>>> number = 5
>>> if number >= 1 and number <= 10:
... print("Inside interval")
... else:
... print("Outside interval")
...
Inside interval
この例に示す and
式を使用すると、指定された数値が 1
から 10
(両方を含む) までの範囲内にあるかどうかを確認できます。
Python には同じ条件を表現するためのショートカットがあります。以下に示すように、連鎖演算子を使用できます。
>>> if 1 <= number <= 10:
... print("Inside interval")
... else:
... print("Outside interval")
...
現在、条件には and
演算子が明示的に含まれていません。ただし、同じ結果が得られます。したがって、両方の条件は同等です。
注: さまざまな方法で演算子をチェーンできます。このトピックについてさらに詳しく知りたい場合は、「Python Booleans: Use Truth Values in Your Code」チュートリアルの「Chaining Comparison Operators」セクションを参照してください。
この例で行ったような演算子の連鎖は、Python のもう 1 つの構文上の糖衣部分です。
三項演算子
Python には三項演算子または条件式と呼ばれる構文構造があります。これらの式は、a ? のような三項演算子からインスピレーションを得ています。 b : c
と呼ばれ、C などの他のプログラミング言語で使用されます。
この構造は、a
の値が true の場合は b
と評価され、それ以外の場合は c
と評価されます。このため、同等の Python 構文は三項演算子とも呼ばれることがあり、次のようになります。
variable = expression_1 if condition else expression_2
この式は、条件が true の場合は expression_1
を返し、それ以外の場合は expression_2
を返します。実際には、この構文は次のような条件文と同等です。
if condition:
variable = expression_1
else:
variable = expression_2
三項演算子は同等の if
… else
ステートメントに置き換えることができるため、この演算子は Python の糖衣構文のもう 1 つの部分であると言えます。
代入式
=
演算子を使用して構築された従来の代入は値を返さないため、式ではなくステートメントになります。対照的に、代入式は値を返す代入です。これらはセイウチ演算子 (:=
) を使用して構築できます。
代入式を使用すると、条件ループや while
ループなどで使用される式の結果を 1 ステップで名前に割り当てることができます。たとえば、単語 "stop"
が入力されるまでキーボードからの入力を受け取る次のループを考えてみましょう。
>>> while (line := input("Type some text: ")) != "stop":
... print(line)
...
Type some text: Python
Python
Type some text: Walrus
Walrus
Type some text: stop
この例では、代入式を使用して line
変数へのユーザーの入力を取得します。同時に、式はユーザーの入力を返し、センチネル値 "stop"
と比較できるようにします。
注: 代入式についてさらに詳しく知りたい場合は、「The Walrus Operator: Python の代入式」を参照してください。
実際には、変数の代入をリフトすることで、セイウチ演算子を使用せずにこのループを書き換えます。
line = input("Type some text: ")
while line != "stop":
print(line)
line = input("Type some text: ")
このコード スニペットは、walurus オペレーターを使用して上で作成したコードと同じように機能します。ただし、演算子はもう方程式に含まれていません。したがって、この演算子は Python の糖衣構文の別の部分であると結論付けることができます。
この例にはさらに欠点があります。input()
の呼び出しが不必要に繰り返されますが、構文的に糖化されたバージョンのコードではこのようなことは起こりません。次のような while
ループを使用して繰り返しをスキップできます。
while True:
line = input("Type some text: ")
if line == "stop":
break
print(line)
このループにより繰り返しが回避されます。ただし、条件がループ内に埋め込まれているため、コード全体を理解するのが少し難しくなります。
Python での解凍
反復可能なアンパックは、Python の優れた機能の 1 つです。反復可能をアンパックするとは、その値を一連の変数に 1 つずつ代入することを意味します。次のセクションでは、反復可能なアンパックが構文糖衣のもう 1 つの部分であることを学びます。
反復可能なアンパック
反復可能なアンパックは、さまざまな状況で使用できる強力な機能です。より読みやすく簡潔なコードを作成するのに役立ちます。
アンパックを使用して、反復可能内の値を一連の変数に分配できます。
>>> one, two, three, four = [1, 2, 3, 4]
>>> one
1
>>> two
2
>>> three
3
>>> four
4
この例では、左側に変数のタプル、右側に値のリストがあります。 Python がこの代入を実行すると、値は位置ごとに対応する変数にアンパックされます。
このコード構造を次の一連の代入に置き換えることができます。
>>> numbers = [1, 2, 3, 4]
>>> one = numbers[0]
>>> one
1
>>> two = numbers[1]
>>> two
2
>>> three = numbers[2]
>>> three
3
>>> four = numbers[3]
>>> four
4
この場合、対応するインデックス操作を使用して、各変数に値を手動で割り当てます。このコードは前のバージョンよりも読みにくくなっていますが、同じ結果が得られます。
アンパックの優れた使用例は、変数間で値を交換する必要がある場合です。解凍機能がない言語では、一時変数を使用する必要があります。
>>> a = 200
>>> b = 400
>>> temp = a
>>> a = b
>>> b = temp
>>> a
400
>>> b
200
この例では、temp
変数を使用して a
の値を保持し、a
と b の間で値を交換できるようにします。
。アンパック構文シュガーを使用すると、次のようなことができます。
>>> a = 200
>>> b = 400
>>> a, b = b, a
>>> a
400
>>> b
200
この例では、強調表示された行が魔法を発揮し、きれいで読みやすい方法で値を交換できるようになります。
*args
および **kwargs
Python では、関数の定義で *args
および **kwargs
構文を使用して、未定義の数の位置引数またはキーワード引数を取る関数を定義できます。 *args
引数は、一連の位置引数をタプルにパックします。
注: 通常、*args
を使用する関数では、args
名と kwargs
名が総称名として使用されます。 > および **kwargs
構文。ただし、名前は単なる慣例です。実際には、任意の名前を使用できます。 *
と **
は、この構文の必須要素です。したがって、*numbers
や **options
などの名前、またはユースケースに適した名前を使用することもできます。
次のおもちゃの例を考えてみましょう。
>>> def show_args(*args):
... print(args)
...
>>> show_args(1, 2, 3, 4)
(1, 2, 3, 4)
この関数は、*args
構文を使用して、不特定の数の位置引数を受け取ることができることを Python に伝えます。位置引数を指定して関数を呼び出すと、それらはタプルにパックされます。
注: *args
と **kwargs
の詳細については、Python args
と を確認してください。 kwargs
: 分かりやすく解説したチュートリアル。
一方、 **kwargs
引数は、キーワード引数を辞書にパックします。
>>> def show_kwargs(**kwargs):
... print(kwargs)
...
>>> show_kwargs(one=1, two=2, three=3, four=4)
{'one': 1, 'two': 2, 'three': 3, 'four': 4}
この例では、**kwargs
構文を使用して、この関数が不定の数のキーワード引数を取ることを Python に伝えます。
注: Python コードでは、*args
と **kwargs
が一緒に使用されていることがよくあります。
>>> def show_arguments(*args, **kwargs):
... print(f"{args = }")
... print(f"{kwargs = }")
...
>>> show_arguments(1, 2, 3, 4, one=1, two=2, three=3, four=4)
args = (1, 2, 3, 4)
kwargs = {'one': 1, 'two': 2, 'three': 3, 'four': 4}
この例では、show_arguments()
は *args
と **kwargs
の両方を受け入れます。一連の位置引数の後にキーワード引数を指定して関数を呼び出すことができます。
*args
をリストまたはタプルに置き換え、**kwargs
を辞書に置き換えることができます。
>>> def show_values(values):
... print(values)
...
>>> show_values([1, 2, 3, 4])
[1, 2, 3, 4]
この例では、*args
を使用する代わりに、位置引数を使用して、値のリストを関数呼び出しに渡します。
**kwargs
を使用して同様のことを実行し、関数呼び出しに辞書を渡すことができます。
>>> def show_items(kwvalues):
... print(kwvalues)
...
>>> show_items({"one": 1, "two": 2, "three": 3, "four": 4})
{'one': 1, 'two': 2, 'three': 3, 'four': 4}
実際には、 *args
と **kwargs
は両方とも、ユーザーの生活をより快適にし、コードをより明示的にするために Python に含まれる構文上の糖衣部分です。
ループと内包表記
ループは、ほとんどのプログラミング言語の基本コンポーネントです。ループを使用すると、反復的なタスクを実行したり、データ ストリームを処理したりできます。 Python には、while
ループと for
ループがあります。 Python には、コンパクトな for
ループのような内包表記もあります。
次のセクションでは、for
ループと内包表記が、while
ループとして書き換えられるため、Python の糖衣構文としても機能することを学びます。
for
ループの探索
for
ループを使用すると、通常は反復可能と呼ばれる特定のデータ ストリームの項目を反復処理できます。リスト、タプル、セット、ディクショナリは、Python の反復可能オブジェクトの良い例です。これらはすべて反復をサポートしています。つまり、for
ループを使用してそれらを走査できます。
注: Python のループについて詳しくは、次のチュートリアルをご覧ください。
- Python の「while」ループ (無限反復)
- Python の「for」ループ (有限反復)
- Python で Do While ループをエミュレートするにはどうすればよいですか?
for
ループのおもちゃの例を次に示します。
>>> numbers = ["one", "two", "three", "four"]
>>> for number in numbers:
... print(number)
...
one
two
three
four
このループは文字列のリストを反復処理し、一度に 1 つの文字列を出力します。 while
ループを作成して、上記のループを置き換えることができます。
>>> numbers = ["one", "two", "three", "four"]
>>> index = 0
>>> while index < len(numbers):
... print(numbers[index])
... index += 1
...
one
two
three
four
この例では、while
ループで同じ反復を実行し、同じ結果を生成しました。コードはあまりきれいで読みにくく見えますが、動作は同じです。したがって、for
ループも Python の糖衣構文であると結論付けることができます。
注: これらの例では、ループは基本的な形式のみを使用しています。 else
句は含まれません。
上の例の while
ループは、ターゲットの反復可能オブジェクトで len()
を呼び出すことができる限り、for
ループの代わりに機能します。実際には、次のようなものが for
ループの動作に近いものになります。繰り返しますが、この例ではループの else
句は考慮されていません。
>>> it = iter(numbers)
>>> while True:
... try:
... number = next(it)
... except StopIteration:
... break
... print(number)
...
one
two
three
four
このループを実装するには、入力データ ストリームから反復子を作成する組み込みの iter()
関数を使用します。ループ内では、組み込みの next()
関数を使用して、ループの各サイクルで反復子から次の項目を取得します。次に、StopIteration
例外を使用して、break
ステートメントでループを終了します。
内包表記の使用
内包表記は Python の特徴的な機能です。内包表記を使用して、データ ストリームから新しいリスト、セット、辞書を作成できます。たとえば、文字列として数値のリストがあり、それを数値に変換して二乗値のリストを作成したいとします。これを行うには、次の内包を使用できます。
>>> numbers = ["2", "9", "5", "1", "6"]
>>> [int(number)**2 for number in numbers]
[4, 81, 25, 1, 36]
この例では、リスト内包表記を使用して数値のリストを反復処理します。内包表記の式は、文字列値を整数値に変換し、その二乗を計算します。その結果、平方数のリストが得られます。
注: リスト内包表記の詳細については、Python でリスト内包表記を使用する場合のチュートリアルを参照してください。
内包表記は人気があり多用途のツールですが、同等の for
ループや while
ループで置き換えることもできます。 for
ループのアプローチのみを考慮してください。
>>> numbers = ["2", "9", "5", "1", "6"]
>>> squares = []
>>> for number in numbers:
... squares.append(int(number)**2)
...
>>> squares
[4, 81, 25, 1, 36]
このコードはより冗長であり、正方形のリストを保存するために追加の変数が必要です。ただし、等価内包と同じ結果が得られます。繰り返しますが、内包表記は Python の糖衣構文です。
演習として、前のセクションで学んだ内容を使用して、理解を while
ループに変換できます。
デコレーター
デコレータは、別の関数を引数として受け取り、明示的に変更することなくその動作を動的に拡張する関数です。 Python には、特定の関数にデコレータを適用できる専用の構文があります。
@decorator
def func():
<body>
この構文の @decorator
部分は、引数として func
オブジェクトを使用して decorator()
を呼び出すように Python に指示します。この操作により、func()
の元の動作を変更し、関数オブジェクトを同じ名前の func
に割り当てることができます。
注: デコレータの詳細については、「Python デコレータ入門」チュートリアルをご覧ください。
デコレータの使用の基本を説明するために、特定の関数の実行時間を測定する必要があるとします。これを行う便利な方法は、次のようなデコレータを使用することです。
>>> import functools
>>> import time
>>> def timer(func):
... @functools.wraps(func)
... def _timer(*args, **kwargs):
... start = time.perf_counter()
... result = func(*args, **kwargs)
... end = time.perf_counter()
... print(f"Execution time: {end - start:.4f} seconds")
... return result
... return _timer
この timer()
関数は、デコレータとして使用するために構築されています。関数オブジェクトを引数として受け取り、拡張関数オブジェクトを返します。 ._timer()
内部関数では、time
モジュールを使用して入力関数の実行時間を測定します。
コードでこのデコレータを使用する方法は次のとおりです。
>>> @timer
... def delayed_mean(sample):
... time.sleep(1)
... return sum(sample) / len(sample)
...
>>> delayed_mean([10, 2, 4, 7, 9, 3, 9, 8, 6, 7])
Execution time: 1.0051 seconds
6.5
この例では、@decorator
構文を使用して layed_mean()
関数を修飾し、その動作を変更します。 layed_mean()
を呼び出すと、時間レポートと期待される結果が得られます。
実際、@decorator
構文を使用しなくても同じ結果が得られます。その方法は次のとおりです。
>>> def delayed_mean(sample):
... time.sleep(1)
... return sum(sample) / len(sample)
...
>>> delayed_mean = timer(delayed_mean)
>>> delayed_mean([10, 2, 4, 7, 9, 3, 9, 8, 6, 7])
Execution time: 1.0051 seconds
6.5
強調表示された行は、関数を @decorator
構文で装飾するのと同じ効果を引き起こします。この割り当てを実行した後は、通常どおり layed_mean()
を使用できます。タイムレポートと計算結果が表示されます。
属性アクセス
Python では、クラスやオブジェクトを操作するときに、 クラスやオブジェクトの属性にアクセスするためにドット表記をよく使用します。つまり、クラス メンバーにアクセスするには、次の構文を使用できます。
obj.attribute
この構文では、ドットを使用して、obj
の attribute
にアクセスする必要があることを表します。このすっきりとした直感的な構文により、コードが読みやすく明確に見えます。ただし、これは糖衣構文でもあります。この構文は、組み込みの getattr()
関数に基づく代替構造に置き換えることができます。
これを説明するために、次の Circle
クラスを考えてみましょう。
from math import pi
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return pi * self.radius**2
def circumference(self):
return 2 * pi * self.radius
このコードでは、インスタンス属性と 2 つのメソッドを使用して Circle
クラスを定義します。属性とメソッドにアクセスするには、ドット表記を使用できます。
>>> from circle import Circle
>>> circle = Circle(10)
>>> circle.radius
10
>>> circle.area()
314.1592653589793
>>> circle.circumference()
62.83185307179586
この例では、ドット表記によって Circle
の特定のインスタンスの属性とメソッドにアクセスできることがわかります。次の構造を使用してこれらのメンバーにアクセスすることもできます。
>>> getattr(circle, "radius")
10
>>> # Method object
>>> getattr(circle, "area")
<bound method Circle.area of <__main__.Circle object at 0x1106d24d0>>
>>> # Method calls
>>> getattr(circle, "area")()
314.1592653589793
>>> getattr(circle, "circumference")()
62.83185307179586
組み込みの getattr()
関数を使用すると、特定のオブジェクトの属性とメソッドにアクセスできます。この関数を使用してメソッドにアクセスすると、メソッド オブジェクトが取得されることに注意してください。メソッドを呼び出したい場合は、必要な引数をかっこのペアに追加する必要があります。
メソッド呼び出し
通常、Python オブジェクトのメソッドを呼び出す方法に関連する糖衣構文がもう 1 つあります。前のセクションの Circle
クラスを続けるには、そのインスタンス メソッドを呼び出す通常の方法は、インスタンスでドット表記を使用することです。
>>> from circle import Circle
>>> circle = Circle(10)
>>> circle.area()
314.1592653589793
>>> circle.circumference()
62.83185307179586
このメソッドの呼び出し方法も糖衣構文です。内部的には、circle.area()
のような処理を実行すると、次のような処理に自動的に変換されます。
>>> Circle.area(circle)
314.1592653589793
この例では、インスタンスを .area()
の self
引数に明示的に渡します。ただし、circle.area()
などでは、Python が self
を提供されたインスタンスに設定します。この動作により、作業が容易になり、コードがクリーンになります。
F 文字列リテラル
フォーマットされた文字列リテラル (略して f-string) も、Python の糖衣構文の一部です。 F 文字列は、最新の Python コードでよく使われています。これらを使用すると、迅速かつクリーンな構文で文字列を補間およびフォーマットすることができます。
注: f-strings やその他の文字列補間および書式設定ツールの詳細については、次のチュートリアルを参照してください。
- 文字列補間と書式設定のための Python の F-String
- 最新の Python 文字列フォーマット ツールのガイド
- Python での文字列補間: 利用可能なツールの探索
- Python 文字列のフォーマット: 利用可能なツールとその機能
- 整った文字列のための Python のフォーマット ミニ言語
コードで f-string を使用する方法の簡単な例を次に示します。
>>> debit = 300
>>> credit = 450
>>> f"Debit: ${debit:.2f}, Credit: ${credit:.2f}, Balance: ${credit - debit:.2f}"
'Debit: $300.00, Credit: $450.00, Balance: $150.00'
この例では、f-string を使用して銀行口座のクイック レポートを作成します。置換フィールドを使用して debit
および credit
変数と書式指定子を挿入して出力を書式設定する方法に注目してください。
f-string を使用する代わりに、文字列 .format()
メソッドを使用できます。
>>> "Debit: ${0:.2f}, Credit: ${1:.2f}, Balance: ${2:.2f}".format(
... debit, credit, credit - debit
... )
'Debit: $300.00, Credit: $450.00, Balance: $150.00'
.format()
メソッドは、同等の f-string と同じ結果を生成します。ただし、その構文は時々読みにくい場合があります。実際には、任意の f-string インスタンスを .format()
の呼び出しで置き換えることができます。したがって、f 文字列も Python の糖衣構文です。
あるいは、+
による文字列連結を使用し、組み込みの format()
関数を呼び出すこともできます。
>>> (
... "Debit: $" + format(debit, ".2f")
... + ", Credit: $" + format(credit, ".2f")
... + ", Balance: $" + format(credit - debit, ".2f")
... )
'Debit: $300.00, Credit: $450.00, Balance: $150.00'
この例では、連結演算子を使用して文字列のさまざまなコンポーネントを連結します。入力値をフォーマットするには、format()
関数を使用します。この構文はかなり複雑ですが、最初の f 文字列と同じように機能します。
アサーション
Python では、アサーションと呼ばれる健全性チェックを作成できます。これらのチェックを記述するには、assert
ステートメントを使用します。アサーションを使用すると、コードの開発中に特定の仮定が正しいかどうかをテストできます。アサーションのいずれかが間違っている場合は、コードにバグがある可能性があります。
注: アサーションの詳細については、Python のアサーション「プロのようにコードをデバッグおよびテストする」を参照してください。
アサーションは主にデバッグ目的で使用されます。これらは、コード内の機能を追加したり他のバグを修正したりする際に、新しいバグが発生しないようにするのに役立ちます。
assert
ステートメントは、次の構文を持つ単純なステートメントです。
assert expression[, assertion_message]
ここで、expression
には任意の有効な Python 式またはオブジェクトを指定でき、これらが真実であるかどうかテストされます。 expression
が false の場合、ステートメントは AssertionError
をスローします。 assertion_message
パラメータはオプションですが、推奨されます。ステートメントが捕らえるべき問題を説明する文字列を保持できます。
このステートメントが実際にどのように機能するかは次のとおりです。
>>> number = 42
>>> assert number > 0, "number must be positive"
>>> number = -42
>>> assert number > 0, "number must be positive"
Traceback (most recent call last):
...
AssertionError: number must be positive
真実の expression
では、最初のアサーションは成功し、何も起こりません。その場合、プログラムは通常の実行を継続します。対照的に、偽の expression
はアサーションを失敗させ、AssertionError
を発生させ、プログラムの実行を中断します。
assert
ステートメントも糖衣構文です。上記のアサーションを次のコードに置き換えることができます。
>>> number = 42
>>> if __debug__:
... if not number > 0:
... raise AssertionError("number must be positive")
...
>>> number = -42
>>> if __debug__:
... if not number > 0:
... raise AssertionError("number must be positive")
...
Traceback (most recent call last):
...
AssertionError: number must be positive
Python の組み込み定数 __debug__
は、assert
ステートメントと密接に関連しています。これはブール定数で、デフォルトは True
です。これは、アサーションが有効であり、Python を通常またはデバッグ モードで実行していることを意味します。
Python を最適化 モードで実行する場合、__debug__
定数は False
になり、アサーションは無効になります。
yield from
構造体
yield from
構造は、Python のもう 1 つの構文糖衣部分です。この構造を使用して、反復可能オブジェクトから項目を生成できます。
この構造の使用方法を示すために、次の Stack
クラスを考えてみましょう。
class Stack:
def __init__(self):
self.items = []
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def __iter__(self):
yield from self.items
この Stack
クラスには、プッシュとポップという 2 つの基本的なスタック操作があります。データを保存するには、.items
という list
オブジェクトを使用します。 .__iter__()
特別メソッドを使用すると、クラスで反復をサポートできるようになります。この例では、yield from
コンストラクトを使用して、.items
リストから値を取得します。構文は非常に読みやすく、明確です。
yield from
構造を少なくとも 2 つの異なるツールに置き換えることができます。そのうちの 1 つは、組み込みの iter()
関数です。
class Stack:
# ...
def __iter__(self):
return iter(self.items)
強調表示された行は、以前のバージョンの .__iter__()
の yield from
構造と同じように機能します。オンデマンドで項目を生成するイテレータを返します。
注: 使用例によっては、yield from
を iter()
に置き換えるのが難しい場合があります。次のおもちゃの例を考えてみましょう。
>>> class Twice:
... def __init__(self, items):
... self.items = list(items)
... def __iter__(self):
... yield from self.items
... print("Halfway there!")
... yield from self.items
...
>>> for number in Twice([1, 2, 3]):
... print(f"-> {number}")
...
-> 1
-> 2
-> 3
Halfway there!
-> 1
-> 2
-> 3
この例では、.__iter__()
の最初の行で return iter(self.items)
を使用しても、return
ステートメントが存在しないため機能しません。残りのコードはアクセスできなくなります。
あるいは、for
ループを使用することもできます。
class Stack:
# ...
def __iter__(self):
for item in self.items:
yield item
この .__iter__()
の別の実装では、オンデマンドで項目を生成するプレーンな yield
ステートメントで明示的な for
ループを使用します。
with
ステートメント
Python の with
ステートメントは、コンテキスト マネージャー オブジェクトを操作できる便利なツールです。これらのオブジェクトは、ファイルなどの外部リソースを扱うときは常に、セットアップ フェーズと破棄フェーズを自動的に処理します。
たとえば、ファイルにテキストを書き込むには、通常、次の構文を使用します。
with open("hello.txt", mode="w", encoding="utf-8") as file:
file.write("Hello, World!")
組み込みの open()
関数は、コンテキスト マネージャー プロトコルをサポートするファイル オブジェクトを返します。したがって、上に示したように、このオブジェクトを with
ステートメントで使用できます。
ステートメントのコード ブロックでは、必要に応じてファイルを操作できます。ファイルを終了すると、with
ステートメントが終了し、ファイルが閉じられ、関連するリソースが自動的に解放されます。
注: with
ステートメントについて詳しくは、コンテキスト マネージャーと Python の with ステートメントのチュートリアルをご覧ください。
with
ステートメントは、セットアップおよびティアダウン ロジックの処理を容易にするもう 1 つの糖衣構文です。このステートメントは、次のような try
… finally
ステートメントを使用して置き換えることができます。
file = open("hello.txt", mode="w", encoding="utf-8")
try:
file.write("Hello, World!")
finally:
file.close()
ここでは、まず open()
を呼び出してファイル オブジェクトを取得します。次に、必要に応じてファイルを操作するための try
ブロックを定義します。 finally
句では、ファイルを手動で閉じて、関連付けられたリソースを解放します。この句は常に実行されるため、ファイルは適切に閉じられるので安心してください。
この例では、finally
句で行うアクションはファイルを閉じることだけです。ただし、この構文を使用して with
ステートメントを置き換える必要がある場合は、finally
句を使用して、ターゲット コンテキスト マネージャーがティアダウン フェーズで実行するアクションを実行する必要があります。これは、 .__exit__()
メソッドによって実行されます。
結論
これで糖衣構文とは何か、そして Python がそれをどのように使用するかがわかりました。また、最も一般的に使用される糖衣構文と、それらがより読みやすく、クリーンで、簡潔で、安全なコードを作成するのにどのように役立つかについても詳しく知ることができます。
このチュートリアルでは次のことを学習しました:
- 糖衣構文とは
- 糖衣構文が演算子にどのように適用されるか
- どのように代入式が糖衣構文であるか
for
ループ と内包表記 が糖衣構文である理由- 他の Python の構造が糖衣構文である仕組み
糖衣構文を使用することは必須ではありませんが、それをワークフローに組み込むことは、コードをより Python らしくするための優れた方法です。