見出し画像

【コンピュータ】初見はつらいよ!優しくない Python 入門

Python は多くの分野で使われている、シンプルで使いやすいプログラミング言語です。その直感的な性質により、入門者にも理解しやすいと思われます。

しかし、中には、初見では理解が難しい機能や、「そんなことできるの?」というような隠れた便利機能もあります。今回は、そのような機能を4つ紹介します。

※本記事で紹介するコードは、Bing AI を参考に作成しています。


f 文字列

文字列の中に、変数の値を直接入れることができる機能です。

f "{ 変数名 }" / F"{ 変数名 }" で使用できます。

# 変数の定義
num = 100

# f文字列の使用
message = f"numの値は{num}です。"

print(message)  # 出力: numの値は100です。

様々な書式設定も可能です。例えば、小数点以下の有効桁数を指定する場合は、次の通り。「.3f」にすると小数点以下3桁が表示されます。

# 変数の定義
num = 3.14159265359

# .2f は小数点以下2桁を意味する
formatted_num = f"{num:.2f}"

print(formatted_num)  # 出力:3.14

補足

※ f 文字列は、Python 3.6 から追加されたもので、それ以前のバージョンでは利用できないことに注意してください。

リスト内包表記

リストの生成を、1行で書くことができる機能です。

例えば、0~9 の数値の二乗のリストを生成するコードは、次の通り。

# リストの生成
squares = [x**2 for x in range(10)]

# 出力:[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
print(squares)

リスト内包表記を使わない場合のコードは、次の通り。

# リストの生成
squares = []

# リストに要素を追加する
for x in range(10):
    squares.append(x**2)

# 出力:[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
print(squares)

条件式を追加することもでき、特定の条件を満たす要素だけをリストに含めることができます。

# リストには、偶数の二乗のみを含める
even_squares = [x**2 for x in range(10) if x % 2 == 0]

# 出力:[0, 4, 16, 36, 64]
print(even_squares)

リスト内包表記を使わない場合のコードは、次の通り。

# リストの生成
even_squares = []

for x in range(10):
    # 偶数の場合、リストに要素を追加する
    if x % 2 == 0:
        even_squares.append(x**2)

# 出力:[0, 4, 16, 36, 64]
print(even_squares)

リスト内包表記のメリット

ループ構造よりもリスト内包表記の方が処理時間が高速である、という点が挙げられます。

例えば、次のコードを試してみます。処理自体は同様ですが、計算量が多くなっています。

import time

# リスト内包表記
start_time = time.time()
squares = [x**2 for x in range(10000000)]
end_time = time.time()
print(f"リスト内包表記の実行時間:{end_time - start_time} 秒")

# ループ構造
start_time = time.time()
squares = []
for x in range(10000000):
    squares.append(x**2)
end_time = time.time()
print(f"ループ構造の実行時間:{end_time - start_time} 秒")

実行結果は、次の通り。(※実行環境により異なります)

1回目:
リスト内包表記の実行時間:7.186979293823242
ループ構造の実行時間:14.296114683151245 秒

2回目:
リスト内包表記の実行時間:7.45315146446228
ループ構造の実行時間:28.694259643554688 秒

リスト内包記法の方が、より安定して速く動作していることが分かります。処理時間の短縮は、待ち時間の短縮と生産性の向上を意味するため、この観点は非常に重要ですね。

ループ構造のメリット

一方、入門者には、ループ構造の方が理解しやすいと思われます。リスト内包表記は、処理内容や条件式が複雑になるにつれて、コードが読みづらくなる可能性があります。

また、デバッグが必要な場合や、各行でどのような処理が行われているのかを明確にしたい場合にも、有効だと思われます。

for-else 文/while-else 文

for/while のループにおいて、最後まで(途中で break されずに)実行された場合にのみ、else を実行する機能です。

条件式の else とは、全く異なる振る舞いをするため、一見しただけでは、コードが間違っていると思うかも・・・。

例えば、リストの中から、find_number の値と一致する要素を検索するコードは、次の通り。

# リストの作成
numbers = [1, 3, 5, 7]

# 検索対象の数
find_number = 4

for num in numbers:
    if num == find_number:
        print(f"{find_number}が見つかりました。")
        break
else:
    print(f"{find_number}はリスト内に存在しません。")
    
# 出力:4はリスト内に存在しません。

find_number がリストに存在すれば、"見つかりました" と表示し、break でループを抜けます。しかし、リストの最後まで探しても見つからない場合は、else が実行され、"存在しません" と表示されます。

というように、ある条件を満たす要素が、リストに存在するかどうかを簡単にチェックすることができます。フラグ用の変数が不要なので、便利な機能の一つです。

ラムダ式(無名関数)

その場で一時的に関数を定義したい場合に、非常に便利な機能です。

主に、リストなど複数の要素からなるオブジェクトを処理する際、map 関数や filter 関数などと組み合わせて使用されます。

基本的な書き方は、次の通り。

lambda 引数: 返り値

map 関数とラムダ式

map 関数は、リストなどの各要素に指定された関数を適用し、新しいオブジェクトを作成する組み込み関数。

変数名 = map(関数, リストなど)

例えば、リストの全要素を2倍にするコードは、次の通り。

# リストの作成
numbers = [0, 1, 2, 3, 4]

# リストの全要素を2倍にする
double_numbers = list(map(lambda x: x * 2, numbers))

# 出力:[0, 2, 4, 6, 8]
print(double_numbers)

filter 関数とラムダ式

filter 関数は、リストなどの各要素に指定された関数を適用し、その関数が True を返す要素だけを抽出して新しいオブジェクトを作成する組み込み関数。

変数名 = filter(関数, リストなど)

リストの中から、30 より小さい要素のみを抽出するコードは、次の通り。

# リストの作成
scores = [100, 65, 20, 15, 40]

# 30 より小さい要素のみを抽出
fail_scores = list(filter(lambda x: x < 30, scores))

# 出力:[20, 15]
print(fail_scores)

つまり、関数を指定する部分を、ラムダ式で直接置き換えることができるという訳です。

1行のコードで済むような短い関数を、わざわざ定義する必要がなく、一時的な使用で定義と実行を同時に行えるので、コード自体もスッキリしますね。

最後に

今回紹介した機能は、仕様や要件により、全てのコードに適用できるという訳ではありません。しかし、適用可能な場合には、コードの短縮や処理効率の向上につながるため、積極的に活用することをオススメします!

私自身もまだ知らない機能が沢山あるので、これからも少しずつ学んでいきたいと思います・・・。

最後になりましたが、数あるサイトの中からこの記事を最後まで見てくださった方にお礼を申し上げます。どうもありがとうございました!

少しでも参考になれれば幸いです。


参考/関連ページ

【f 文字列】

【リスト内包表記】

【for-else 文/while-else 文】

【リスト内包表記 / for-else 文】

【ラムダ式(無名関数)】

この記事が気に入ったらサポートをしてみませんか?