Skip to content
This page has been auto-translated and may contain errors.View in English

モジュールと標準ライブラリ

docs.scrimba.com

Pythonには膨大な組み込みツールが用意されています。乱数生成、数学演算、日付、ファイルパスなど、様々なものです。これらのツールはモジュールに存在し、importでコードに組み込みます。既にファイルと例外の章でimport jsonを使用しました。この章ではインポートについて完全に説明し、標準ライブラリの最も便利な部分を紹介します。

Pythonの標準ライブラリは、一般的な問題に対するテスト済みでドキュメント化されたソリューションを提供します。モジュールはコード整理の単位です。各ファイルがモジュール、__init__.pyを含む各ディレクトリがパッケージです。importシステムはモジュールを探し、必要に応じてコンパイルし、sys.modulesにキャッシュするため、モジュールは1回だけロードされます。

importは実際の処理を行います。Pythonはモジュールを探し、1回実行して、sys.modules(既にロードされたすべてのモジュールの辞書)にキャッシュします。同じ名前を2回目にインポートすると、再実行ではなく高速ルックアップとなります。import requestsは、モジュールオブジェクトを現在の名前空間(コード内の特定の時点で見える名前の表)にrequestsという名前でバインドします。from requests import getは同じロード処理を実行しますが、getだけをバインドします。実際のプロジェクトで価値があるのは、Pythonがどこを検索するか(sys.path)、ディレクトリがどのようにインポート可能なパッケージになるか(__init__.py)、循環インポートを避ける方法です。これらはすべて以下で説明されています。

モジュールのインポート

最もシンプルなインポートは、モジュール全体を取り込み、ドット記法でその内容を使用できます。モジュールから特定の名前をインポートして、プレフィックスなしで直接使用することもできます。エイリアスは長い名前を短縮します。

import moduleは、モジュールオブジェクトを現在のスコープの名前moduleにバインドします。from module import nameは名前nameだけをバインドします。エイリアス(import module as alias)はサードパーティライブラリで一般的です。from module import *は避けてください。名前空間が汚染され、名前がどこから来たのか不明確になります。

from module import nameは処理をスキップしません。Pythonは依然としてモジュール全体をロードして実行し、その後、要求した1つの名前だけをバインドします。知っておくべき落とし穴は循環インポートです。2つのモジュールがまだロード中に互いにインポートしようとするため、一方は半分構築されたモジュールを見て、名前が不足しています。通常の修正は、それを必要とする関数内にオフェンディングimportを移動する(両方のモジュールのロードが終了した後に実行される)か、共有コードを両方がインポートできる3番目のモジュールに抽出することです。実行時にのみ知っているモジュール名をインポートする必要がある場合、importlib.import_module("name")は名前を文字列として受け取ります。

python
import math

math.sqrt(16)     # 4.0
math.pi           # 3.141592653589793
math.floor(3.9)   # 3
math.ceil(3.1)    # 4

モジュールから特定の名前をインポートして、直接使用できるようにします。

python
from math import sqrt, pi

sqrt(16)    # 4.0("math."プレフィックスは不要)
pi          # 3.141592653589793

モジュールまたは名前にエイリアスを付けて短縮します。

python
import math as m

m.sqrt(16)    # 4.0

from math import sqrt as square_root
square_root(25)    # 5.0

エイリアスは一般的なサードパーティライブラリで一般的です(import numpy as npimport pandas as pd)。標準ライブラリモジュールの場合は、完全な名前を使用することをお勧めします。コードがより読みやすくなります。

Junoモジュールのインポートimport mathはモジュール全体を取り込み、ドットで内側に到達します。math.sqrt(16)from math import sqrtは1つの名前を取得し、プレフィックスを削除できます。asキーワードは長いインポートの名前を変更しますが、標準ライブラリのものについては完全な名前の方がより明確に読めます。
Junoモジュールのインポートimport moduleはモジュールオブジェクトをバインドし、from module import nameは1つの名前をバインドし、import module as aliasはそれの名前を変更します。from module import *をスキップしてください。すべての名前をスコープにダンプし、それぞれがどこから来たのかを隠します。
Junoモジュールのインポートfrom module import nameはモジュール全体をロードしても、保持する名前は1つだけです。最終的に直面する問題は循環インポートです。2つのモジュールがロード中に互いにインポートします。そのimportを関数の内側に移動するか、共有コードを3番目のモジュールに分割します。実行時に名前しか知らない場合は、importlib.import_module()があります。

random

randomモジュールは乱数を生成し、ランダムな選択を行います。ゲーム、シミュレーション、ランダムサンプリング、予測不可能性が必要なその他の用途に使用します。シードを設定すると、結果が再現可能になります。同じシードは毎回同じシーケンスを生成します。

randomはMersenne Twisterの疑似乱数生成器を使用します。シードは完全なシーケンスを決定します。同じシードは常に同じ出力を生成します。.choice()は1つのアイテムを選択し、.choices()は復元ありで選択し、.sample()は復元なしで選択します。.shuffle()はリストをインプレイスで修正し、Noneを返します。

random疑似乱数を生成します。ランダムに見えますが、開始値(シード)で駆動される固定式から生成されるため、同じシードはすべてのマシンで同じシーケンスを生成します。これがテストを再現可能にする理由です。本番環境で重要なルールは、パスワード、セッショントークン、パスワードリセットコードなど、人が悪用する可能性のあるものにはrandomを使用しないことです。設計上、予測可能なため、十分な出力を見た攻撃者は残りを推測できます。これらの場合は、オペレーティングシステムの安全な乱数性を利用するsecretsモジュールに到達してください。random.SystemRandom()は、APIを切り替えたくない場合、同じ安全なソースを使い慣れたrandomメソッド名の背後で提供します。

python
import random

random.random()              # 0から1の間の浮動小数点数(0と1を除く)
random.randint(1, 10)        # 1から10の整数(両端を含む)
random.uniform(1.0, 10.0)    # 1.0から10.0の間の浮動小数点数

colours = ["red", "green", "blue"]
random.choice(colours)       # 1つのアイテムを選択
random.choices(colours, k=3) # k個のアイテムを選択(復元あり)
random.sample(colours, k=2)  # k個のアイテムを選択(復元なし)

numbers = [1, 2, 3, 4, 5]
random.shuffle(numbers)      # インプレイスでシャッフル、Noneを返す

再現可能な結果を得るために(テストとデータ科学に便利)、生成する前にシードを設定します。

python
random.seed(42)
random.randint(1, 100)   # シード42では常に同じ値

同じシードは毎回、任意のマシンで同じシーケンスを生成します。

Junorandomrandom.choice()はリストから1つのアイテムを選択し、random.randint(1, 10)は範囲内の整数を与えます。端を含むです。すべての実行で同じ結果が必要ですか(たとえば、テストの場合)?random.seed()を最初に呼び出すとシーケンスがロックインされます。
Junorandom.choice()は1つを選択し、.choices()は復元ありで選択し、.sample()は復元なしで選択します。.shuffle()はリストをインプレイスで並べ替え、Noneを返すため、`nums = random.shuffle(nums)`と書いてはいけません。シードはシーケンス全体を固定し、ランダムテストを繰り返し可能にする方法です。
Junorandom `random`は疑似乱数で、設計上予測可能なため、ゲームやテストに適していますが、攻撃者が悪用する可能性のあるものには不適切です。トークン、パスワード、リセットコードには`secrets`を使用してください。繰り返したい場合のために`random.seed()`を保持します。

math

mathモジュールは、数値の章で説明した基本算術演算子を超えた、より高度な数学演算を追加します。平方根、べき乗、対数、三角関数、piと無限大などの特殊な値がすべてここにあります。

mathはC言語レベルの標準数学関数の実装を提供します。math.pow()は常にfloatを返すのに対し、Pythonの**演算子は整数ベースと指数に対してintを返すことに注意してください。math.log(x, base)は任意の底への対数を計算し、math.log(x)は自然対数を計算します。

実際のコードで問題になる詳細は、nan(「数字ではない」の略で、0/0または失敗した解析などの未定義の結果から得られる浮動小数点数)とinf(無限大)です。nanは何とも等しくなく、それ自体とも等しくないため、x == float("nan")は常にFalseです。つまり、==でテストすることはできません。math.isnan(x)を使用し、math.isinf(x)を無限大用に使用してください。その他の習慣:2つの浮動小数点数を比較する場合、a == bよりもmath.isclose(a, b)を優先します。浮動小数点丸めにより、正確な等式は信頼できないためです。1つずつではなく、数字の配列全体に対する数学については、numpyが標準ツールですが、このガイドの範囲外です。

python
import math

math.sqrt(25)        # 5.0
math.pow(2, 10)      # 1024.0(2 ** 10と同じですが常にfloatを返す)
math.log(100, 10)    # 2.0(底が10の対数)
math.log(math.e)     # 1.0(自然対数)

math.sin(math.pi / 2)   # 1.0
math.cos(0)             # 1.0

math.ceil(3.2)    # 4
math.floor(3.9)   # 3
math.trunc(3.9)   # 3(正数の場合はint()と同じ)

math.inf          # 無限大
math.isnan(float("nan"))   # True
math.isinf(math.inf)       # True
Junomathmath+ - * /の先にあるすべてをカバーします。平方根、べき乗、対数、三角関数、および`math.pi`などの定数。計算が基本演算子より多くを必要とする瞬間に到達し、式を自分で書く必要をスキップします。
Junomath `math`は平方根、対数、三角関数を持っています。注意すべき点は1つ。`math.pow(2, 10)`は常に`float`を返しますが、`2 ** 10`は整数の入力に対して`int`のままです。`math.log(x, base)`は任意の底を取り、`math.log(x)`は自然対数です。
Junomath 落とし穴は`nan`と`inf`です。`nan`は決して自分自身と等しくないため、`==`ではなく`math.isnan()`でテストします。浮動小数点数を比較するには、丸めが正確な等式を信頼できなくするため、`==`ではなく`math.isclose()`を使用してください。数字の配列全体については、それは`numpy`の領域です。

datetime

datetimeモジュールは日付と時刻を処理します。datetime.now()は現在の日付と時刻を返します。strftime()は文字列としてフォーマットします。strptime()は文字列を日時に解析します。timedeltaは加算または減算できる期間を表します。

datetimedatetimedeltaが主要なクラスです。strftime()はフォーマットコードを使用して日時を文字列としてフォーマットします。strptime()はパターンを指定して文字列を解析します。timedeltaは算術をサポートします。日時から期間を加算または減算し、<>-で日時を比較できます。

本番での落とし穴は、プレーンなdatetime.now()ナイーブであることです。タイムゾーンが付属していないため、世界のどの部分を表しているのか実際には分かりません。異なるマシンからの2つのナイーブな日時は比較可能に見えますが、静かに比較できず、その曖昧性はオフバイアワー(時間単位)のバグを引き起こします。修正はアウェアな日時(タイムゾーンを持つもの)で作業し、システム間で保存または送信されるものはUTCに標準化することです。datetime.now(timezone.utc)。ローカル時間に変換するのは、エッジでのみ、人に表示する場合です。zoneinfoモジュールを"Europe/Oslo"などの名前が付いたゾーン用に使用し、夏時間の変更を自動的に処理します。もう1つのルール。経過時間をdatetime.now()の差で測定しないでください。システムクロックは飛ぶ可能性があります(同期または手動変更)。time.perf_counter()を使用してください。前方にしか移動しないカウンター。期間のため。

python
from datetime import datetime, date, timedelta

now = datetime.now()             # 現在の日付と時刻
today = date.today()             # 現在の日付のみ

print(now.year, now.month, now.day)
print(now.hour, now.minute, now.second)

# フォーマット
print(now.strftime("%Y-%m-%d"))           # "2024-01-15"
print(now.strftime("%d %B %Y, %H:%M"))   # "15 January 2024, 09:42"

# 解析
deadline = datetime.strptime("2024-12-31", "%Y-%m-%d")

# 算術
tomorrow = today + timedelta(days=1)
next_week = today + timedelta(weeks=1)
diff = deadline - now
print(f"{diff.days} days until deadline")

一般的なstrftimeコード:

コード意味
%Y4桁の年2024
%m月(ゼロパディング)01
%d日(ゼロパディング)15
%H時間(24時間)09
%M42
%B月の完全名January
Junodatetimedatetime.now()は現在の日付と時刻を提供します。strftime()は`%Y-%m-%d`などのコードで文字列に変換し、`strptime()`は逆に、文字列を解析して戻します。timedeltaは加算または減算できる期間なので、`today + timedelta(days=1)`は明日です。
Junodatetime `datetime`、`date`、`timedelta`がコアです。`strftime()`はコードでフォーマットし、`strptime()`はパターンで解析します。日付は算術を実行します。2つを減算すると`timedelta`が得られ、`timedelta`を加算して前後に移動します。
Junodatetime プレーンな`datetime.now()`はナイーブで、タイムゾーンなし。これは2台のマシンが関与するとすぐに静かに壊れます。`datetime.now(timezone.utc)`でUTCを保存して渡し、表示用にのみローカルに変換し、名前が付いたゾーンのために`zoneinfo`に頼ります。経過時間を`time.perf_counter()`で測定し、決して`now()`の差を使用しないでください。ウォールクロックは飛ぶ可能性があります。

os と pathlib

pathlibはファイルパスを操作する最新の方法です。Pathオブジェクトは、/演算子を使用してパスを構築、検査、ナビゲートできます。osはオペレーティングシステムへのアクセスと環境変数を提供します。新しいコードではpathlibを優先してください。

pathlib.Pathはファイルシステムパスをオブジェクトとして表現し、クエリとナビゲーション用のメソッドがあります。/演算子はパスコンポーネントをクリーンに結合し、OS固有の区切り文字を自動的に処理します。os.environは環境変数用の辞書のようなオブジェクトです。os.environ.get("KEY", "default")は欠落している変数に対して安全です。

Pathはオペレーティングシステムに自動的に適応するため、同じコードがすべてのマシンで正しい区切り文字でパスを結合します。Path("data") / "file.csv"を書き、"data/" + nameの手で作られた文字列を決して書かないでください。Windowsで壊れます。2つの実用的なメモ。まず、.glob().rglob().iterdir()ジェネレータ(完全なリストを構築するのではなく、エントリを1つずつ生成)を返すため、2回ループするか、事前にカウントを知る必要がある場合はlist()でラップしてください。巨大なディレクトリの場合、遅延反復が目安です。次に、少数の古いライブラリはプレーンな文字列ではなくPathオブジェクトを期待します。1つがPathを拒否する場合、str(path)を渡して先に進みます。環境変数を読み取る場合、常にos.environ.get("KEY", "default")を使用し、os.environ["KEY"]ではなく、インデックス形式は変数がセットされていない場合にKeyErrorを発生させます。これは新しいデプロイメントで一般的なケースです。

python
from pathlib import Path

p = Path("data/reports")

p.exists()           # パスが存在する場合はTrue
p.is_dir()           # ディレクトリの場合はTrue
p.is_file()          # ファイルの場合はTrue

p.mkdir(parents=True, exist_ok=True)   # ディレクトリを作成

for f in p.glob("*.csv"):              # ディレクトリ内のすべてのCSVファイル
    print(f.name)                      # ファイル名

report = p / "report_jan.csv"          # /演算子がパスを結合
report.stem       # "report_jan"(拡張子なし)
report.suffix     # ".csv"
report.parent     # Path("data/reports")

content = report.read_text()           # ファイルの内容を直接読み取る
report.write_text("new content\n")    # 直接書き込み

osモジュールの場合:

python
import os

os.getcwd()                        # 現在の作業ディレクトリ
os.listdir(".")                    # ディレクトリの内容を一覧表示
os.path.exists("data.txt")        # パスが存在する場合はTrue
os.path.join("data", "file.txt")  # "data/file.txt"(クロスプラットフォーム)
os.environ.get("HOME")            # 環境変数を読み取る

新しいコードではpathlibを優先してください。osは環境変数が必要な場合や、文字列を期待する古いAPIを使用する場合に使用します。

Junoos と pathlib `pathlib.Path`はファイルパスをオブジェクトとして扱います。`.exists()`、`.read_text()`、`.write_text()`、`.glob()`で調べることができます。`/`演算子はピースを結合するため、`p / "report.csv"`は実際のパスのように読めます。新しいコードでは古い`os.path`よりも`pathlib`に到達してください。
Junoos と pathlib `Path`は`/`で結合し、OS区切り文字を処理するため、パスはポータブルなままです。`os.environ`は環境変数用の辞書のようで、`os.environ.get("KEY", "default")`は安全な読み取りで、キーがない場合にはエラーが発生しません。
Junoos と pathlib `Path`と`/`でパスを構築し、Windowsで壊れる接着文字列を決して作成しないでください。`.glob()`とその仲間はジェネレータを返すため、2回ループする必要がある場合は`list()`してください。環境変数をブラケット形式で読み取り、`os.environ.get(key, default)`を使用してください。この形式は変数がセットされていない瞬間に`KeyError`を発生させ、これは正確に新規デプロイケースです。

timeit

timeitはコード実行にかかる時間を測定します。2つのアプローチを比較して、より速いものを選択する場合に便利です。安定した測定を得るために、コードを何度も実行します。

timeit.timeit(stmt, setup, number)stmtnumber回実行して、経過時間の合計を秒単位で返すことでタイミングを測定します。setup文字列はタイムされたループの前に1回実行されます。結果をnumberで割ると、呼び出しごとの時間が得られます。より多くの繰り返しでシステムスケジューリング分散を減らします。

timeitは正しいツールです。マイクロベンチマーク:分離で1つの小さなスニペットをタイミングし、スケジューリング分散が平均化されるように何度も実行します。これはノイズを抑えていますが、単一の実行は依然として信頼できないため、1つの数ではなく複数の繰り返しの最適なものを取ります。避けるべき間違いは、プログラム全体のスローダウンを見つけるためにそれを使用することです。渡したスニペットだけをタイミングするため、実際にどの関数が遅いのかを教えることはできません。そのためにはcProfileを使用してください。実際のプログラムを実行し、時間がどこに行ったかを報告します。経験則:timeitで2つの実装を比較し、cProfileで最初の場所でボトルネックを見つけます。

python
import timeit

# 単一のステートメントをタイムする
timeit.timeit("sum(range(1000))", number=10000)

# より複雑なブロックをタイムする
setup = "data = list(range(1000))"
code = "[x * 2 for x in data]"
time = timeit.timeit(code, setup=setup, number=10000)
print(f"{time:.4f} seconds for 10,000 runs")

numberは繰り返す回数です。より多くの繰り返しは、より安定した測定を提供します。

Junotimeit `timeit.timeit()`はコード片を何度も実行してタイミングを計測し、その後実行回数で割って安定した1回当たりの数を得ます。2つのうち「どちらが速いか」を推測する代わりに決定する方法です。1回の実行はノイズが多すぎて信頼できないため、ループさせます。
Junotimeit `timeit.timeit(stmt, setup, number)`はその回数`stmt`を実行して、合計秒数を返します。`setup`文字列はループの前に1回実行されます。`number`で割ると1回当たりの時間が得られ、繰り返しを増やしてスケジューリングノイズを沈めます。
Junotimeit `timeit`はマイクロベンチマーク用。2つの小さなスニペットを比較し、複数実行の最良値を使用します。実際のプログラムで遅い関数を見つけることはできません。渡したスニペットだけをタイミングするため。そのために`cProfile`を使用し、修正を比較するために`timeit`を使用します。

string

stringモジュールは、文字、数字、句読点用の事前構築された文字列定数を提供します。文字を検査したり、特定のアルファベットからランダム文字列を生成する必要があるときに便利です。

stringモジュール定数(ascii_lettersdigitspunctuation)はプレーンな文字列で、インデックス、反復、またはinで使用できます。random.choices()と組み合わせて、ランダムトークンまたはパスワードを生成する標準的な方法です。

これらの定数はプレーンな文字列なので、char in string.ascii_lettersをチェックすると、毎回文字列全体をスキャンします。そのスキャンは**O(n)**です。文字列の長さで作業が増えます。1回は大丈夫、タイトなループでは無駄です。メンバーシップを繰り返しテストする場合は、1回セットを構築してください(letters = set(string.ascii_letters))。代わりにそれに対してチェックしてください。セットルックアップは、保持するエントリの数に関係なく、高速なままです。もう1つの便利な部分はstring.Templateで、プレーン$name置換を行います。ユーザー入力または設定ファイルからテンプレートが来る場合、信頼できないテキストをf文字列またはstr.format()に渡すよりも安全です。変数またはメソッドに到達することはできません。

python
import string

string.ascii_lowercase   # "abcdefghijklmnopqrstuvwxyz"
string.ascii_uppercase   # "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
string.ascii_letters     # 両方が結合
string.digits            # "0123456789"
string.punctuation       # すべての句読点文字

文字を検査したりランダム文字列を生成する必要があるときに便利です。

python
import string, random

chars = string.ascii_letters + string.digits
password = "".join(random.choices(chars, k=12))
Junostring `string`モジュールはすぐに使える文字セットを提供します。`string.ascii_letters`、`string.digits`、`string.punctuation`。これらはプレーンな文字列で、ループするか、サンプリングできます。既知のアルファベットで構築または確認する必要があるときはいつでも便利です。
Junostring `string.ascii_letters`、`string.digits`などはプレーンな文字列で、インデックス、反復、`in`でテストできます。`random.choices()`と組み合わせて、ランダムトークンまたはパスワードの標準レシピを取得します。`random`は本当のシークレットには安全ではないことに注意してください。
Junostring 定数はプレーンな文字列なので、`char in string.ascii_letters`は毎回全体をスキャンします。ループで確認する場合は1回`set`を構築してください。ユーザー入力からのテンプレートについては、`string.Template`で`$name`がf文字列より安全です。変数に到達できません。

独自のモジュール作成

すべてのPythonファイルはモジュールです。別のファイルから使用するには、ファイル名で(.pyなし)インポートします。モジュール全体をインポートしてドット記法でその内容を使用するか、特定の名前をインポートして直接使用できます。

Pythonはモジュールをインポートする場合、ファイルを上から下へ1回実行し、結果をsys.modulesにキャッシュします。同じモジュールの後続のインポートは、ファイルを再実行せずにキャッシュされたオブジェクトを返します。より大きなプロジェクトでは、モジュールはパッケージに編成されます。__init__.pyファイルがあるディレクトリ。

import utilsを書くと、Pythonは実行したスクリプトのフォルダから始まるsys.path内のディレクトリを順番に検索します。これは最も一般的な「マイマシンで動作する」インポートバグの源です。別の作業ディレクトリからファイルを実行し、それが期待するフォルダはパス上にない可能性があります。インポートが失敗します。信頼できる修正は、緩いファイルを指し示すのではなく、プロジェクトをパッケージとして実行することです(python -m mypackage.main)。パッケージは、__init__.pyファイル(空でも構いません)を持つモジュールのディレクトリです。存在は、Pythonに対してフォルダがインポート可能であることを通知するものです。パッケージ内で、from . import helpersのような相対インポートは、「この同じパッケージから」を意味し、パッケージの名前を変更または移動してもインポートが動作し続けるようにします。1つのシャープエッジ。importlib.reload()はモジュールを再実行しますが、既にインポートした名前は古いバージョンを指すため、リロードはREPLでの簡単な実験を超えて信頼できません。

python
# utils.py
def clamp(value, lo, hi):
    return max(lo, min(value, hi))

PI = 3.14159
python
# main.py
import utils

utils.clamp(150, 0, 100)   # 100
utils.PI                    # 3.14159

from utils import clamp
clamp(50, 0, 100)           # 50

Pythonはインポートするファイルと同じディレクトリ(および他のいくつかの場所)を見ることでモジュールを見つけます。より大きなプロジェクトの場合、モジュールはパッケージに編成されます。__init__.pyファイルを持つディレクトリ。

JunoCreating your own modules すべての`.py`ファイルは既にモジュールです。ファイル名をその`.py`なしでインポートし、その関数と変数はあなたのものです。`import utils`、その後`utils.clamp(...)`、または1つの名前を`from utils import clamp`で引き出します。これは成長するプログラムをファイル間で分割する方法です。
JunoCreating your own modules モジュールをインポートすると、上から下へ1回実行してから、`sys.modules`にキャッシュするため、後続のインポートはファイルを再実行せずに同じオブジェクトを返します。トップレベルコードを軽いままにしてください。その理由で、何か重いものはインポート時に実行されます。関連モジュールをパッケージにグループ化します。`__init__.py`を持つフォルダ。
JunoCreating your own modules インポートは`sys.path`を通じて解決され、スクリプト自身のフォルダから始まります。これが、緩いファイルを間違ったディレクトリから実行するとインポートが壊れる理由です。代わりにパッケージとして実行してください。`python -m pkg.main`。そして`importlib.reload()`を簡単なREPLポーク以上信頼しないでください。既にインポートした名前は古いバージョンを指し続けるため。

__name__ == "__main__"

Pythonがファイルを直接実行する場合、__name__"__main__"に設定されます。同じファイルがモジュールとしてインポートされる場合、__name__はモジュール名です。このパターンは、ファイルを直接実行するときは実行されるが、別のモジュールによってインポートされるときはスキップされるコードを記述できます。

if __name__ == "__main__":は実行可能なモジュールコードの標準的なガード。モジュールを(その関数を公開)インポート可能にし、(テストまたはデモコード付き)直接実行可能にします。なしでは、モジュールをインポートするとトップレベルコードが実行され、ほぼ決して望まれません。

Pythonは、実際に実行したファイルに対して__name__"__main__"に設定し、インポートされたものに対してそのモジュール自身の名前に設定します。ガードは、インポート時の副作用を保つために存在します。モジュールがロードされるときに何かを行うコード(引数の解析、接続の開始、デモの実行など)は、別のファイルがあなたをインポートする瞬間に発火しません。保持するパターン。実際の作業をmain()関数に入れ、ガードの下で呼び出すため、インポーターはスタートアップなしで関数を取得し、ファイルは単独で実行されます。ガードをスキップすることは、テストスイートがモジュールをインポートする瞬間に誰かのデモコードを神秘的に実行する古典的な理由です。

python
# utils.py
def clamp(value, lo, hi):
    return max(lo, min(value, hi))

if __name__ == "__main__":
    # これは以下の場合にのみ実行されます:python utils.py
    # 以下の場合ではなく:import utils
    print(clamp(150, 0, 100))   # 100

これはモジュールとしても単独のスクリプトとしても有用なファイルの標準パターンです。

Juno__name__ == '__main__'if __name__ == "__main__":は1つのファイルを、インポート可能なモジュールと実行可能なスクリプトの両方にします。ガードの下のコードは`python utils.py`を実行するときに実行され、別のファイルが`import utils`を実行するときはスキップされます。モジュールの下部に簡単なデモまたはテストを格納するのに便利です。
Juno__name__ == '__main__' `__name__`は直接実行したファイルでのみ`"__main__"`です。ガードはデモまたはテストコードがモジュールをインポートするときに実行されないようにします。そうでなければ、静かに発生します。ファイルがライブラリとスクリプトの両方として機能する標準的な方法です。
Juno__name__ == '__main__' ガードはインポート時の副作用を停止し、引数解析、デモ、接続は誰かがあなたをインポートするときに発火しません。仕事を`main()`に置いてガードの下で呼び出します。インポーターは関数を取得し、ファイルは単独で実行されます。それをスキップして、テストスイートがモジュールをインポートする瞬間にデモを実行するのを見てください。

標準ライブラリのハイライト

知る価値のあるいくつかのモジュール。それぞれが、自分で実装するのに大きな作業を要する一般的な問題を解決します。

標準ライブラリは広範です。以下のハイライトは、本番環境コードで最も頻繁に遭遇するもの。完全なリファレンスについては、docs.python.org/3/libraryが権威ある情報源です。

標準ライブラリは、テスト済みでドキュメント化されたモジュールの厳選セットです。サードパーティパッケージに到達する前に、標準ライブラリに解決策があるかどうかを確認してください。functoolsitertoolscontextlibdataclassestypingabcはそれぞれ、サードパーティパッケージが頻繁に再発明するツールを提供します。

collections: 特殊化されたコンテナタイプ:

python
from collections import Counter, defaultdict, deque

Counter(["a", "b", "a", "c", "a"])   # Counter({'a': 3, 'b': 1, 'c': 1})
defaultdict(list)                      # 不足キーを自動作成する辞書
deque([1, 2, 3], maxlen=5)            # 両端からの高速append/pop

itertools: イテラブル処理用ツール:

python
import itertools

list(itertools.chain([1, 2], [3, 4]))          # [1, 2, 3, 4]
list(itertools.islice(range(100), 5))          # [0, 1, 2, 3, 4]
list(itertools.combinations([1, 2, 3], 2))     # [(1, 2), (1, 3), (2, 3)]
list(itertools.product([0, 1], repeat=2))      # [(0,0), (0,1), (1,0), (1,1)]

sys: Pythonインタプリタへのアクセス:

python
import sys

sys.argv        # コマンドライン引数のリスト
sys.exit(1)     # ステータスコード付きで終了
sys.version     # Pythonバージョン文字列

サードパーティパッケージ: 標準ライブラリを超えて、pipはコミュニティパッケージをインストール:

bash
pip install requests    # HTTPライブラリ
pip install pandas      # データ操作
pip install numpy       # 数値計算

サードパーティパッケージはこのガイドの範囲外ですが、パターンは常に同じです。pip install、その後import

実践で

randomstringdatetimeを組み合わせて、タイムスタンプ付きのユニークなゲームIDを生成します。

python
import random
import string
from datetime import datetime

def generate_game_id(length: int = 8) -> str:
    chars = string.ascii_uppercase + string.digits
    return "".join(random.choices(chars, k=length))

def timestamp() -> str:
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

game_id = generate_game_id()
print(f"[{timestamp()}] Starting game {game_id}")

scores = [random.randint(50, 100) for _ in range(5)]
print(f"Round scores: {scores}")
print(f"Best: {max(scores)}")

pathlibdatetimeを使用して、ディレクトリ内のファイルを検索してそのサイズをレポート:

python
from pathlib import Path
from datetime import datetime

def find_files(directory: str, pattern: str = "*.csv") -> list[Path]:
    return sorted(Path(directory).glob(pattern))

def timestamp() -> str:
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

files = find_files(".", "*.md")[:3]
print(f"[{timestamp()}] Found {len(files)} file(s)")
for f in files:
    size = f.stat().st_size if f.exists() else 0
    print(f"  {f.name} ({size} bytes)")

環境変数から型付きデフォルト付きのアプリ設定を読み取り、改行で区切られたJSON構造化アクセスログエントリを作成:

python
import os
import json
from datetime import datetime
from pathlib import Path

def load_env_config() -> dict:
    return {
        "debug": os.environ.get("DEBUG", "false").lower() == "true",
        "port": int(os.environ.get("PORT", "8080")),
        "log_level": os.environ.get("LOG_LEVEL", "INFO"),
    }

def write_access_log(method: str, path: str, status: int) -> None:
    log_dir = Path("logs")
    log_dir.mkdir(exist_ok=True)
    entry = {
        "ts": datetime.now().isoformat(),
        "method": method,
        "path": path,
        "status": status,
    }
    with open(log_dir / "access.jsonl", "a") as f:
        f.write(json.dumps(entry) + "\n")

config = load_env_config()
print(f"Starting on port {config['port']}, debug={config['debug']}")
write_access_log("GET", "/users", 200)

改行で区切られたJSON(.jsonl)は一般的なログ形式です。各行は有効なJSONオブジェクトで、ストリーム、追記、ファイル全体をロードせずに行ごとに解析するのが簡単です。