はじめに
Hello World とコメント
Python はコメントに # を使用し、ドキュメント文字列には三重引用符を使用します。print() 関数は sep と end パラメータをサポートし、出力フォーマットをカスタマイズできます。ドキュメント文字列は help() と __doc__ でアクセス可能なドキュメントとして機能します。
# This is a single-line comment
"""
This is a
multi-line comment (docstring)
"""
print("Hello, World!") # print to stdout
print("A", "B", "C", sep="-") # A-B-C
print("No newline", end="") # suppress newlineインデントとコードブロック
ほとんどの言語とは異なり、Python はコードブロックを定義するために中括弧ではなくインデントを使用します。一貫性が重要です — タブとスペースを混用すると SyntaxError が発生します。PEP 8 ではレベルごとに 4 スペースを推奨しています。
# Python uses indentation (4 spaces) to define blocks
if True:
print("inside if")
if True:
print("nested block")
print("outside block")
# No braces! Indentation IS the syntax
def func():
x = 1
return x + 1入力と出力
input() は stdin から文字列として読み取ります — 数値が必要な場合は必ず変換してください。変換には int()、float() などを使用します。F-strings(Python 3.6+)が文字列をフォーマットする推奨方法です。
# input() always returns a string
name = input("Enter your name: ")
age = int(input("Enter your age: ")) # convert to int
print(f"Hello {name}, you are {age} years old")
# formatted output
print("Pi is approximately {:.2f}".format(3.14159))
print(f"{1000000:,}") # 1,000,000 with thousands separator複数文と行継続
セミコロンを使用して 1 行に複数の文を区切ります(慣用的な Python では稀です)。長い行はバックスラッシュで継続するか、()、[]、{} の中で自動的に継続できます。可読性のため、暗黙の継続を優先してください。
# multiple statements on one line (discouraged)
a = 1; b = 2; c = 3
# explicit line continuation
total = 1 + 2 + 3 + \
4 + 5 + 6
# implicit continuation inside brackets
nums = [
1, 2, 3,
4, 5, 6
]
result = (1 + 2
+ 3 + 4)Python の実行
Python スクリプトは 'python script.py' で実行します。REPL は対話的な実験を可能にします。python が Python 2 を指すシステムでは必ず python3 を使用してください。shebang 行により、Unix 上でスクリプトが実行可能になります。
# Run a script
# $ python script.py
# Run interactively (REPL)
# $ python
# >>> 2 + 2
# 4
# Shebang line for Unix scripts
#!/usr/bin/env python3
# Check Python version
import sys
print(sys.version)
print(sys.version_info.major) # 3変数とデータ型
変数と動的型付け
Python は動的型付けを使用します — 変数は実行時に型を変更できます。type() で確認し、isinstance() で検証します。Python 3.6+ は型ヒント(name: str = 'Alice')をサポートし、実行時の強制なしで IDE サポートを提供します。
# Python is dynamically typed - no declaration needed
name = "Alice" # str
age = 30 # int
height = 5.7 # float
is_active = True # bool
items = [1, 2, 3] # list
# Type checking
print(type(name)) # <class 'str'>
print(isinstance(age, int)) # True
# Multiple assignment
x, y, z = 1, 2, 3
a = b = 0 # chain assignment型ヒント(Python 3.6+)
型ヒントはコードの可読性を向上させ、IDE の自動補完と mypy による静的解析を可能にします。実行時には強制されません — Python は動的型付けのままです。None になり得る値には Optional[X] を使用してください。
# Variable annotations
name: str = "Alice"
age: int = 30
scores: list[float] = [90.5, 85.0]
# Function annotations
def greet(name: str, times: int = 1) -> str:
return (f"Hi {name}! " * times).strip()
# Optional and Union
from typing import Optional, Union
def find(id: int) -> Optional[str]:
return "Alice" if id == 1 else None
# mypy for static type checking
# $ mypy script.py型変換
Python には組み込みの変換関数があります:int()、float()、str()、bool()、list()、tuple()、set()、dict()。偽値には 0、''、[]、{}、None、False が含まれます。int() はゼロに向かって切り捨て、round() は銀行家丸めを使用します。
# String to number
num_str = str(42) # "42"
num = int("42") # 42
float_num = float("3.14") # 3.14
# Number conversions
print(int(3.99)) # 3 (truncates toward zero)
print(int(-3.99)) # -3
print(round(3.14159, 2)) # 3.14
# Boolean conversion
print(bool(0)) # False
print(bool("")) # False
print(bool([])) # False
print(bool("anything")) # True
# Collection conversions
print(list("abc")) # ['a', 'b', 'c']
print(tuple([1, 2, 3])) # (1, 2, 3)
print(set([1, 1, 2])) # {1, 2}数値型
Python の整数は任意精度を持ちます(オーバーフローなし)。浮動小数点数は IEEE 754 倍精度で、通常の精度問題があります。複素数は組み込みです。ブール値は int のサブクラスです(True==1、False==0)。可読性のため、数値リテラルにアンダ ースコアを使用してください。
# Integers (arbitrary precision)
big = 10 ** 100 # no overflow
print(type(big)) # <class 'int'>
# Floats (IEEE 754 double)
pi = 3.14159
print(0.1 + 0.2) # 0.30000000000000004
# Complex numbers
z = 3 + 4j
print(z.real, z.imag) # 3.0 4.0
print(abs(z)) # 5.0
# Boolean is subclass of int
print(isinstance(True, int)) # True
print(True + True) # 2
# Underscores in numbers (3.6+)
million = 1_000_000
binary = 0b_1010_1010定数と命名規則
Python には const キーワードがありません — ALL_CAPS 名は慣習のみで定数です(再代入を防ぐものはありません)。PEP 8 は命名を定義しています:変数/関数には snake_case、クラスには PascalCase、定数には ALL_CAPS。先頭のアンダースコアは慣習的に「プライベート」を意味し、二重アンダースコアは名前マングリングを引き起こします。
# Python has no true constants - convention only
MAX_SIZE = 100 # ALL_CAPS for constants
PI = 3.14159
# Naming conventions (PEP 8)
variable_name = "snake_case" # variables, functions
ClassName = "PascalCase" # classes
CONSTANT_VALUE = 100 # constants
_private_var = "underscore prefix" # private (convention)
__name_mangled = "double underscore" # name mangling
# dunder names (reserved)
__name__, __main__, __init__文字列
文字列メソッド
文字列は不変です — メソッドは新しい文字列を返します。find() は見つからない場合は -1 を返し、index() は ValueError を発生させます。検証には isalpha()/isdigit()/isalnum() を使用してください。str クラスには 40 以上のメソッドがあります — dir(str) で探索してください。
s = "Hello, World"
# Case operations
print(s.upper()) # HELLO, WORLD
print(s.lower()) # hello, world
print(s.title()) # Hello, World
print(s.capitalize()) # Hello, world
print(s.swapcase()) # hELLO, wORLD
# Search & replace
print(s.find("World")) # 7 (index, -1 if not found)
print(s.index("World")) # 7 (raises ValueError if not found)
print(s.replace("o", "0")) # Hell0, W0rld
print(s.count("l")) # 3
# Validation
print("abc".isalpha()) # True
print("123".isdigit()) # True
print(" ".isspace()) # True文字列フォーマット
F-strings は文字列をフォーマットする現代的で最速かつ最も読みやすい方法です。コロンの後にフォーマット指定をサポートします::.2f は小数点以下 2 桁、:>10 は右揃え幅 10、:, は千位区切り。新しいコードでは %-フォーマットを避けてください。
name = "Alice"
age = 30
# f-strings (Python 3.6+) - PREFERRED
print(f"Hello, {name}! You are {age}.")
print(f"{name.upper()} is {age * 365} days old")
print(f"{3.14159:.2f}") # 3.14
print(f"{42:>10}") # right-align
print(f"{42:<10}") # left-align
print(f"{42:^10}") # center
print(f"{1000000:,}") # 1,000,000
# str.format() method
print("Hello, {}!".format(name))
print("{name} is {age}".format(name="Bob", age=25))
# Old style (avoid in new code)
print("Hello, %s!" % name)スライスとインデックス
Python のスライス構文 [start:stop:step] は強力です — stop は排他的です。負のインデックスは末尾から数えます。s[::-1] は文字列を反転させる慣用的な方法です。スライスは安全です:範囲外のインデックスはエラーを発生させず、空の文字列を返します。
s = "Hello, World"
# Indexing (0-based, negative from end)
print(s[0]) # H
print(s[-1]) # d
print(s[7]) # W
# Slicing [start:stop:step]
print(s[0:5]) # Hello
print(s[7:]) # World
print(s[:5]) # Hello
print(s[::2]) # HloWrd (every 2nd char)
print(s[::-1]) # dlroW ,olleH (reverse!)
# Length
print(len(s)) # 12
# Slicing never raises IndexError
print(s[100:200]) # '' (empty string)分割と結合
split() は文字列をリストに分割し、join() はリストを文字列に結合します。多くの文字列を効率的に連結するには常に join() を使用してください — + 演算子は中間文字列を生成します。partition() は正確に 3 つの部分(前、区切り文字、後)に分割します。
# Split
csv = "a,b,c,d"
print(csv.split(",")) # ['a', 'b', 'c', 'd']
print(csv.split(",", 2)) # ['a', 'b', 'c,d'] (max 2 splits)
# Splitlines
text = "line1\nline2\nline3"
print(text.splitlines()) # ['line1', 'line2', 'line3']
# Partition (splits on first occurrence)
print("[email protected]".partition("@"))
# ('user', '@', 'domain.com')
# Join
words = ["Hello", "World"]
print(" ".join(words)) # Hello World
print("-".join(["2024", "01", "15"])) # 2024-01-15
print("".join(["a", "b", "c"])) # abc
# String concatenation
s = "Hello" + " " + "World"
parts = ["a"]
parts += "b" # NOT string concat - adds chars to list!削除とパディング
strip() はデフォルトで前後の空白を削除し、指定した文字も削除できます。zfill() は先頭にゼロを埋めます(ID に便利)。rjust/ljust/center は指定した幅にパディングし、オプションで埋め文字を指定できます。
# Strip whitespace (or specified chars)
s = " hello "
print(s.strip()) # "hello"
print(s.lstrip()) # "hello "
print(s.rstrip()) # " hello"
# Strip specific characters
print("xxxhelloxxx".strip("x")) # hello
# Padding / centering
print("42".zfill(5)) # 00042
print("hi".rjust(10)) # " hi"
print("hi".ljust(10, "-")) # "hi--------"
print("hi".center(10, "*")) # "****hi****"
# expandtabs
print("a\tb".expandtabs(4)) # "a b"Raw 文字列とエスケープ
Raw 文字列(r'...')はバックスラッシュを文字通りに扱います — 正規表現パターンや Windows ファイルパスに不可欠です。三重引用符文字列は改行を保持します。文字列は繰り返しに * 演算子を、連結に + をサポートします。
# Escape sequences
print("Line1\nLine2") # newline
print("Tab\there") # tab
print("Quote: \"hi\"") # escaped quotes
print("Backslash: \\") # literal backslash
# Raw strings (ignore escapes) - great for regex
path = r"C:\Users\name\file.txt"
regex = r"\d{3}-\d{4}"
print(path) # C:\Users\name\file.txt
# Triple-quoted strings
multi = """
Multiple
lines
"""
# String multiplication
print("ab" * 3) # ababab数値と数学
算術演算子
Python には 7 つの算術演算子があります。/ は常に float を返し、// は切り捨て除算(負の無限大に向かって丸める)です。** はべき乗です(^ は XOR です)。% 演算子の結果は C/Java とは異なり、除数の符号を取ります。
# Basic operators
print(7 + 3) # 10 addition
print(7 - 3) # 4 subtraction
print(7 * 3) # 21 multiplication
print(7 / 3) # 2.333... true division (always float)
print(7 // 3) # 2 floor division
print(7 % 3) # 1 modulo (remainder)
print(7 ** 3) # 343 exponentiation
# Floor division with negatives
print(-7 // 3) # -3 (rounds toward negative infinity)
print(-7 % 3) # 2 (result has same sign as divisor)
# Augmented assignment
x = 10
x += 5 # x = x + 5
x **= 2 # x = x ** 2Math モジュール
math モジュールは数学関数と定数を提供します。すべての三角関数はラジアンを使用します — math.radians()/degrees() で変換してください。math.gcd() は最大公約数を求めます。複素数には cmath モジュールを使用してください。
import math
# Constants
print(math.pi) # 3.141592653589793
print(math.e) # 2.718281828459045
print(math.inf) # inf
print(math.nan) # nan
# Functions
print(math.sqrt(16)) # 4.0
print(math.pow(2, 10)) # 1024.0
print(math.log(100, 10)) # 2.0 (log base 10)
print(math.log(math.e)) # 1.0 (natural log)
print(math.factorial(5)) # 120
print(math.gcd(12, 8)) # 4
# Rounding
print(math.floor(3.7)) # 3
print(math.ceil(3.2)) # 4
print(math.trunc(-3.7)) # -3 (toward zero)
# Trigonometry (radians)
print(math.sin(math.pi / 2)) # 1.0
print(math.degrees(math.pi)) # 180.0Random モジュール
random モジュールはメルセンヌツイター PRNG を使用します — 暗号学的に安全ではありません。セキュリティには secrets モジュールを使用してください。random.sample() は一意の項目を選び、random.choices() は重複を許可します。テストで再現可能な結果を得るためにシードを設定してください。
import random
# Random integers
print(random.randint(1, 100)) # 1 to 100 inclusive
print(random.randrange(0, 10, 2)) # even number 0,2,4,6,8
# Random floats
print(random.random()) # 0.0 to 1.0
print(random.uniform(1.0, 10.0)) # random float in range
# Choice & sampling
colors = ["red", "green", "blue"]
print(random.choice(colors)) # one random item
print(random.sample(colors, 2)) # 2 unique items
print(random.choices(colors, k=5)) # 5 items (with replacement)
# Shuffle (in-place)
nums = [1, 2, 3, 4, 5]
random.shuffle(nums)
print(nums)
# Reproducible randomness
random.seed(42) # same seed = same sequenceDecimal と Fractions
浮動小数点の精度エラーが許容されない金融計算(例:お金)には Decimal を使用してください。正確な有理数演算には Fraction を使用してください。どちらも float より遅いですが、丸め誤差を回避します。Decimal は float ではなく文字列から構築してください。
from decimal import Decimal, getcontext
from fractions import Fraction
# Float precision issues
print(0.1 + 0.2) # 0.30000000000000004
# Decimal for exact decimal arithmetic
a = Decimal("0.1")
b = Decimal("0.2")
print(a + b) # 0.3 (exact!)
# Set precision
getcontext().prec = 6
print(Decimal(1) / Decimal(7)) # 0.142857
# Fractions for exact rational arithmetic
f1 = Fraction(1, 3)
f2 = Fraction(1, 6)
print(f1 + f2) # 1/2
print(float(f1)) # 0.3333...
# Fraction from string
print(Fraction("3/4")) # 3/4ビット演算子
ビット演算子は整数の個々のビットを操作します。Python の整数は任意精度を持つため、シフトは固定幅の言語とは異なる動作をします。一般的な用途:フラグ、マスク、低レベルプロトコルの解析。x & (x-1) == 0 は x が 2 のべき乗かどうかを確認します。
# Bitwise operators work on integers
a = 0b1010 # 10
b = 0b1100 # 12
print(a & b) # 8 (0b1000) AND
print(a | b) # 14 (0b1110) OR
print(a ^ b) # 6 (0b0110) XOR
print(~a) # -11 (NOT, two's complement)
print(a << 2) # 40 (left shift, multiply by 4)
print(a >> 1) # 5 (right shift, divide by 2)
# Binary representation
print(bin(10)) # 0b1010
print(hex(255)) # 0xff
print(oct(8)) # 0o10
print(int("1010", 2)) # 10 (parse binary)
# Common tricks
print(5 & 1) # 1 (check odd: nonzero = odd)
print(8 & (8-1)) # 0 (check power of 2)データ構造
リスト
リストは Python の最も汎用的なデータ構造です — 順序付き、変更可能、異種混合です。append() は O(1)、insert(0, x) は O(n) です。両端での高速な操作には collections.deque を使用してください。sort() はインプレースで、sorted() は新しいリストを返します。
# Lists are ordered, mutable sequences
nums = [1, 2, 3, 4, 5]
mixed = [1, "hello", True, 3.14]
# Adding elements
nums.append(6) # [1,2,3,4,5,6]
nums.insert(0, 0) # [0,1,2,3,4,5,6]
nums.extend([7, 8]) # extend with another list
# Removing elements
nums.remove(0) # remove by value
popped = nums.pop() # remove & return last
popped = nums.pop(0) # remove & return by index
del nums[0] # delete by index
nums.clear() # remove all
# Slicing (same as strings)
nums = [1, 2, 3, 4, 5]
print(nums[1:3]) # [2, 3]
print(nums[::-1]) # [5, 4, 3, 2, 1] reverse
# Sorting
nums.sort() # in-place sort
nums.sort(reverse=True) # descending
sorted_nums = sorted(nums) # returns new listタプル
タプルは不変で、リストより高速です。固定のコレクション、複数の戻り値、辞書のキー(リストはキーにできません)に使用してください。名前付きタプルは可読性のためのフィールド名を提供します。単一要素のタプルには末尾のカンマが必要です。
# Tuples are ordered, IMMUTABLE sequences
point = (3, 4)
single = (42,) # note the comma for single-element tuple
empty = ()
# Packing & unpacking
coordinates = 10, 20, 30 # packing
x, y, z = coordinates # unpacking
x, y = y, x # swap values!
# Multiple return values
def min_max(nums):
return min(nums), max(nums)
lo, hi = min_max([3, 1, 4, 1, 5])
# Named tuples (readable)
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
p = Point(3, 4)
print(p.x, p.y) # 3 4
print(p[0], p[1]) # 3 4
# Tuples are immutable but can contain mutable objects
t = (1, [2, 3])
t[1].append(4) # OK: (1, [2, 3, 4])辞書
辞書はハッシュマップです — 検索/挿入/削除は平均 O(1) です。キーはハッシュ可能(不変)でなければなりません。Python 3.7 以降、dict は挿入順序を維持します。KeyError を回避するには get() を使用してください。dict 内包表記は辞書を簡潔に作成します。
# Dicts are key-value mappings (insertion-ordered since 3.7)
user = {"name": "Alice", "age": 30}
# Access
print(user["name"]) # Alice
print(user.get("email")) # None (no KeyError)
print(user.get("email", "N/A")) # N/A (default)
# Add/update
user["email"] = "[email protected]" # add
user["age"] = 31 # update
user.setdefault("role", "user") # set if missing
# Delete
del user["email"]
val = user.pop("age") # remove & return
# user.clear() # remove all
# Iteration
for key in user: # keys
print(key)
for k, v in user.items(): # key-value pairs
print(k, v)
for v in user.values(): # values
print(v)
# Dict comprehension
squares = {x: x**2 for x in range(5)}
# Merge dicts (3.9+)
merged = {"a": 1} | {"b": 2}セット
セットは一意でハッシュ可能な要素の順序なしコレクションです。メンバーシップテスト(リストの O(n) に対して O(1))と集合演算(和、積、差)に優れています。frozenset は不変でハッシュ可能です。順序は保証されません。
# Sets are unordered collections of unique elements
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
# Set operations
print(a | b) # union: {1, 2, 3, 4, 5, 6}
print(a & b) # intersection: {3, 4}
print(a - b) # difference: {1, 2}
print(a ^ b) # symmetric difference: {1, 2, 5, 6}
# Methods
a.add(5) # add element
a.discard(10) # remove if present (no error)
a.remove(1) # remove (KeyError if missing)
a.update([6, 7]) # add multiple
# Membership test (O(1) - faster than list)
print(3 in a) # True
# Frozen set (immutable)
fs = frozenset([1, 2, 3])
# Common use: deduplicate
unique = list(set([1, 1, 2, 2, 3])) # [1, 2, 3]内包表記
内包表記はコレクションを簡潔に作成する Pythonic な方法です。ジェネレータ式(括弧の代わりに丸括弧)は遅延評価です — 要求に応じて値を生成し、メモリを節約します。可読性のため、map()/filter() より内包表記を優先してください。
# List comprehension
squares = [x**2 for x in range(10)]
evens = [x for x in range(20) if x % 2 == 0]
pairs = [(x, y) for x in range(3) for y in range(3)]
# Dict comprehension
square_map = {x: x**2 for x in range(5)}
# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# Set comprehension
unique_lens = {len(w) for w in ["a", "ab", "abc", "ab"]}
# Generator expression (lazy, memory-efficient)
gen = (x**2 for x in range(1000000))
print(next(gen)) # 0
print(next(gen)) # 1
total = sum(x**2 for x in range(100)) # no extra list
# Nested comprehension (matrix)
matrix = [[i * 3 + j for j in range(3)] for i in range(3)]
# [[0,1,2], [3,4,5], [6,7,8]]Collections モジュール
collections モジュールは特殊なコンテナを提供します。Counter はハッシュ可能な項目をカウントします。defaultdict は欠落キーを自動作成します。deque は両端で O(1) の append/pop を提供します(リストの O(n) に対して)。これらはクリーンで効率的なコードに不可欠です。
from collections import Counter, defaultdict, deque, OrderedDict
# Counter - counting
words = ["apple", "banana", "apple", "cherry", "banana", "apple"]
cnt = Counter(words)
print(cnt) # Counter({'apple': 3, 'banana': 2, 'cherry': 1})
print(cnt.most_common(2)) # [('apple', 3), ('banana', 2)]
# defaultdict - no KeyError
dd = defaultdict(list)
dd["fruits"].append("apple")
dd["fruits"].append("banana")
# dd["vegs"] automatically creates empty list
# deque - fast double-ended queue
dq = deque([1, 2, 3])
dq.appendleft(0) # [0, 1, 2, 3]
dq.append(4) # [0, 1, 2, 3, 4]
dq.popleft() # 0, deque is now [1, 2, 3, 4]
dq.rotate(1) # rotate right
# OrderedDict (less needed since 3.7, dicts are ordered)
od = OrderedDict([("a", 1), ("b", 2)])制御フロー
If / Elif / Else
Python は if/elif/else を使用します — 'elseif' ではなく 'elif' であることに注意してください。インデントがブロックを定義します。三項演算子 'x if cond else y' は式です。Python は空のコレクション、0、None、False を偽として扱います — 簡潔な条件分岐に便利です。
score = 85
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
else:
grade = "F"
print(f"Grade: {grade}") # Grade: B
# Conditional expression (ternary)
status = "pass" if score >= 60 else "fail"
# Truthy/falsy values
# Falsy: False, 0, 0.0, "", [], {}, (), None
# Everything else is truthy
if []: # False
print("never")
if [0]: # True (non-empty list)
print("always")For ループと反復
Python の for ループは任意のイテラブルを反復します。range() は数値を生成します(stop は排他的)。enumerate() は項目とインデックスをペアにします。zip() は複数のシーケンスを並列で反復します。dict のキーと値のペアを反復するには .items() を使用してください。
# range(start, stop, step)
for i in range(5): # 0, 1, 2, 3, 4
print(i)
for i in range(2, 10, 2): # 2, 4, 6, 8
print(i)
for i in range(10, 0, -1): # countdown
print(i)
# Iterate over collections
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)
# enumerate for index + value
for idx, fruit in enumerate(fruits):
print(f"{idx}: {fruit}")
# zip to iterate multiple sequences
names = ["Alice", "Bob"]
ages = [30, 25]
for name, age in zip(names, ages):
print(f"{name}: {age}")
# Iterate dict
user = {"name": "Alice", "age": 30}
for key, value in user.items():
print(f"{key} = {value}")While ループと Break/Continue
while ループは条件が真の間繰り返します。break はループを即座に終了し、continue は次の反復にスキップします。for/else 構文はループが break されなかった場合にのみ else ブロックを実行します。pass は空のブロックのプレースホルダーです。
# Basic while
count = 0
while count < 5:
print(count)
count += 1
# break - exit loop
while True:
cmd = input("> ")
if cmd == "quit":
break
print(f"You said: {cmd}")
# continue - skip to next iteration
for i in range(10):
if i % 2 == 0:
continue # skip even numbers
print(i) # prints 1, 3, 5, 7, 9
# else clause (runs if no break)
for i in range(5):
if i == 10:
break
else:
print("Loop completed without break")
# pass - do nothing (placeholder)
for i in range(5):
pass # TODO: implementMatch 文(Python 3.10+)
match 文(Python 3.10+)は強力な構造的パターンマッチングで、C の switch をはるかに超えます。シーケンス、マッピング、クラスインスタンスにマッチし、変数をバインドできます。_ パターンはワイルドカード(デフォルト)です。'if' によるガードで条件を追加できます。
# Structural pattern matching (like switch)
def handle_command(cmd):
match cmd.split():
case ["quit"]:
return "Goodbye"
case ["hello", name]:
return f"Hello, {name}!"
case ["move", direction] if direction in "NSEW":
return f"Moving {direction}"
case ["add", x, y]:
return int(x) + int(y)
case _:
return "Unknown command"
print(handle_command("hello Alice")) # Hello, Alice!
# Matching data structures
match point:
case (0, 0):
print("origin")
case (0, y):
print(f"on y-axis at {y}")
case (x, 0):
print(f"on x-axis at {x}")
case (x, y):
print(f"at ({x}, {y})")イテレータとジェネレータ
ジェネレータは yield を使用して値を遅延生成します — すべての値を前もって計算せず、メモリを節約します。イテレータプロトコル(iter() と next())を実装します。一度使い切ると終了です。大きな/無限のシーケンス、パイプライン、ストリーミングデータにジェネレータを使用してください。
# Iterator protocol
nums = [1, 2, 3]
it = iter(nums)
print(next(it)) # 1
print(next(it)) # 2
print(next(it)) # 3
# next(it) # StopIteration
# Generator function (uses yield)
def count_up_to(n):
count = 1
while count <= n:
yield count
count += 1
for num in count_up_to(5):
print(num) # 1, 2, 3, 4, 5
# Infinite generator
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
fib = fibonacci()
print(next(fib)) # 0
print(next(fib)) # 1
print(next(fib)) # 1
print(next(fib)) # 2
# Generator expression
squares = (x**2 for x in range(10))関数
関数の定義と呼び出し
関数は def で定義します。デフォルト引数には = を使用します。Python は明確さのためにキーワード引数をサポートします。関数は複数の値を(タプルとして)返すことができます。ドキュメント文字列(三重引用符)は関数を文書化し、help() でアクセスできます。
# Basic function
def greet(name):
return f"Hello, {name}!"
print(greet("Alice")) # Hello, Alice!
# Default arguments
def greet(name, greeting="Hello"):
return f"{greeting}, {name}!"
print(greet("Bob")) # Hello, Bob!
print(greet("Bob", "Hi")) # Hi, Bob!
# Keyword arguments
print(greet(name="Carol", greeting="Hey"))
# Return multiple values (tuple)
def stats(nums):
return min(nums), max(nums), sum(nums) / len(nums)
lo, hi, avg = stats([1, 2, 3, 4, 5])
# Docstrings
def add(a, b):
"""Add two numbers and return the result.
Args:
a: First number
b: Second number
Returns:
Sum of a and b
"""
return a + b引数:*args と **kwargs
*args は余分な位置引数をタプルに集め、**kwargs は余分なキーワード引数を dict に集めます。args/kwargs という名前は慣習です。関数呼び出し時に * でシーケンスを、** で dict を展開できます。順序:位置引数、*args、キーワード引数、**kwargs。
# *args - variable positional arguments (tuple)
def sum_all(*args):
return sum(args)
print(sum_all(1, 2, 3)) # 6
print(sum_all(1, 2, 3, 4, 5)) # 15
# **kwargs - variable keyword arguments (dict)
def print_info(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
print_info(name="Alice", age=30, role="admin")
# Combining all
def func(a, b, *args, **kwargs):
print(f"a={a}, b={b}")
print(f"args={args}")
print(f"kwargs={kwargs}")
func(1, 2, 3, 4, x=5, y=6)
# a=1, b=2, args=(3, 4), kwargs={'x': 5, 'y': 6}
# Unpacking arguments
nums = [1, 2, 3]
print(sum_all(*nums)) # unpack list as args
opts = {"name": "Alice", "age": 30}
print_info(**opts) # unpack dict as kwargsLambda と高階関数
Lambda は単一の式に制限されます — 複雑なロジックには def を使用してください。sorted()、map()、filter() のような高階関数の引数として優れています。ただし、リスト内包表記は map/filter より読みやすいことが多いです。reduce() は functools にあります。
# Lambda - anonymous function (single expression)
square = lambda x: x ** 2
print(square(5)) # 25
# Common with sorted, map, filter, reduce
students = [("Alice", 85), ("Bob", 92), ("Carol", 78)]
# Sort by score (key function)
sorted_by_score = sorted(students, key=lambda s: s[1])
# [('Carol', 78), ('Alice', 85), ('Bob', 92)]
# map - apply function to each item
nums = [1, 2, 3, 4, 5]
doubled = list(map(lambda x: x * 2, nums))
# [2, 4, 6, 8, 10]
# filter - keep items where function returns True
evens = list(filter(lambda x: x % 2 == 0, nums))
# [2, 4]
# reduce - accumulate to single value
from functools import reduce
product = reduce(lambda a, b: a * b, nums)
# 120 (1*2*3*4*5)
# Prefer comprehensions over map/filter
doubled = [x * 2 for x in nums] # more Pythonic
evens = [x for x in nums if x % 2 == 0]デコレータ
デコレータは元のコードを変更せずに動作を追加するために関数をラップします。@構文は糖衣構文です。引数付きデコレータは追加のネストレベルが必要です。元の関数のメタデータ(名前、ドキュメント文字列)を保持するには、常に functools.wraps を使用してください。
# A decorator modifies a function's behavior
def uppercase_result(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result.upper()
return wrapper
@uppercase_result
def greet(name):
return f"hello, {name}"
print(greet("alice")) # HELLO, ALICE
# Decorator with arguments
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def say_hi():
print("Hi!")
say_hi() # prints "Hi!" three times
# Practical: timing decorator
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(f"{func.__name__} took {time.time() - start:.4f}s")
return result
return wrapper
# Use functools.wraps to preserve metadata
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapperスコープとクロージャ
Python は LEGB スコープ順序で名前を解決します:Local、Enclosing、Global、Built-in。関数内でグローバル変数を再バインドするには 'global' を使用してください。囲みスコープの変数を変更するには 'nonlocal'(Python 3)を使用してください。クロージャは囲みスコープを記憶します。
# LEGB rule: Local, Enclosing, Global, Built-in
x = "global"
def outer():
x = "enclosing"
def inner():
x = "local"
print(x) # local
inner()
print(x) # enclosing
outer()
print(x) # global
# global keyword - modify global variable
count = 0
def increment():
global count
count += 1
# nonlocal keyword - modify enclosing variable
def make_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
c = make_counter()
print(c()) # 1
print(c()) # 2
print(c()) # 3オブジェクト指向とクラス
クラスとオブジェクト
クラスはデータ(属性)と振る舞い(メソッド)を束ねます。__init__ はコンストラクタです。self はインスタンスを参照します(他の言語の 'this' に相当)。クラス変数は共有され、インスタンス変数はオブジェクトごとです。__str__ はユーザー向け、__repr__ は開発者向けです。
class Dog:
# Class variable (shared by all instances)
species = "Canis familiaris"
# Constructor
def __init__(self, name, age):
# Instance variables
self.name = name
self.age = age
# Instance method
def bark(self):
return f"{self.name} says Woof!"
# String representation
def __str__(self):
return f"Dog({self.name}, {self.age})"
# Official representation (for debugging)
def __repr__(self):
return f"Dog(name='{self.name}', age={self.age})"
# Create instances
buddy = Dog("Buddy", 3)
lucy = Dog("Lucy", 5)
print(buddy.bark()) # Buddy says Woof!
print(buddy.name) # Buddy
print(buddy.species) # Canis familiaris
print(str(buddy)) # Dog(Buddy, 3)継承とポリモーフィズム
継承によりクラスは振る舞いを再利用・拡張できます。Python は MRO(メソッド解決順序)による多重継承をサポートし、競合を解決します。ポリモーフィズムは異なる型を統一的に扱うことを可能にします。型チェックには type() ではなく isinstance() を使用してください。
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError("Subclass must implement")
class Dog(Animal):
def speak(self):
return f"{self.name} says Woof!"
class Cat(Animal):
def speak(self):
return f"{self.name} says Meow!"
# Polymorphism - same interface, different behavior
def animal_sound(animal):
print(animal.speak())
animals = [Dog("Buddy"), Cat("Whiskers")]
for a in animals:
animal_sound(a)
# Buddy says Woof!
# Whiskers says Meow!
# Multiple inheritance
class Swimmer:
def swim(self):
return "swimming"
class Flyer:
def fly(self):
return "flying"
class Duck(Animal, Swimmer, Flyer):
pass
duck = Duck("Donald")
print(duck.swim()) # swimming
print(duck.fly()) # flying
# Check inheritance
print(isinstance(duck, Animal)) # True
print(issubclass(Dog, Animal)) # Trueプロパティとカプセル化
Python には真の private/protected はありません — 慣習を使用します。単一のアンダースコア _ は「内部」を意味します。二重アンダースコア __ は名前マングリングを引き起こします(真のプライバシーではありません)。@property はメソッドをゲッター/セッター付きの属性に変え、検証と計算プロパティを可能にします。
class Temperature:
def __init__(self, celsius=0):
self.celsius = celsius # uses setter below
# Getter
@property
def celsius(self):
return self._celsius
# Setter
@celsius.setter
def celsius(self, value):
if value < -273.15:
raise ValueError("Below absolute zero!")
self._celsius = value
# Computed property
@property
def fahrenheit(self):
return self._celsius * 9/5 + 32
@fahrenheit.setter
def fahrenheit(self, value):
self.celsius = (value - 32) * 5/9
temp = Temperature(25)
print(temp.fahrenheit) # 77.0
temp.fahrenheit = 100
print(temp.celsius) # 37.78...
# Name conventions:
# _name - protected (convention, not enforced)
# __name - private (name mangling: _ClassName__name)
# __name__ - dunder (reserved by Python)クラスメソッドとスタティックメソッド
@staticmethod はクラス名前空間内の単なる関数です — 暗黙の第一引数はありません。@classmethod は第一引数としてクラス(cls)を受け取り、代替コンストラクタ(ファクトリメソッド)や継承対応の振る舞いに便利です。コンストラクタには classmethod を、ユーティリティ関数には staticmethod を使用してください。
class MathUtils:
pi = 3.14159
# Static method - no self/cls, lives in class namespace
@staticmethod
def add(a, b):
return a + b
# Class method - receives the class as first argument
@classmethod
def circle_area(cls, radius):
return cls.pi * radius ** 2
# Alternative constructor (common classmethod use)
@classmethod
def from_diameter(cls, diameter):
return cls() # would configure instance
# Static: called on class or instance, no special first arg
print(MathUtils.add(2, 3)) # 5
# Class: often used for alternative constructors
print(MathUtils.circle_area(5)) # 78.54...
# Factory pattern with classmethod
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
@classmethod
def origin(cls):
return cls(0, 0)
@classmethod
def from_tuple(cls, coords):
return cls(*coords)
p1 = Point.origin()
p2 = Point.from_tuple((3, 4))マジックメソッド(Dunder)
マジックメソッド(dunder メソッド)は演算子オーバーロードとプロトコルの振る舞いを実装します。+ には __add__、== には __eq__、len() には __len__、反復/アンパックには __iter__。これらにより、オブジェクトが Python の組み込み構文や関数で自然に動作します。
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
# String representation
def __str__(self):
return f"Vector({self.x}, {self.y})"
# Operator overloading
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
# Equality
def __eq__(self, other):
return self.x == other.x and self.y == other.y
# Length
def __len__(self):
return int((self.x**2 + self.y**2) ** 0.5)
# Make it iterable
def __iter__(self):
yield self.x
yield self.y
# Index access
def __getitem__(self, index):
return (self.x, self.y)[index]
v1 = Vector(2, 3)
v2 = Vector(4, 5)
print(v1 + v2) # Vector(6, 8)
print(v1 * 3) # Vector(6, 9)
print(v1 == Vector(2, 3)) # True
print(len(v1)) # 3
x, y = v1 # unpacking via __iter__エラー処理
Try / Except / Finally
try/except/else/finally:try はリスクのあるコードを実行し、except はエラーをキャッチし、else は例外がなければ実行され、finally は常に実行されます(クリーンアップ)。単なる 'except:' ではなく、具体的な例外をキャッチしてください。クリーンアップが成功時のみ行われるべき場合に else ブロックが便利です。Exception はほとんどのキャッチ可能なエラーの基底です。
# Basic exception handling
try:
result = 10 / 0
except ZeroDivisionError as e:
print(f"Error: {e}") # division by zero
finally:
print("This always runs")
# Multiple exception types
try:
value = int("abc")
except (ValueError, TypeError) as e:
print(f"Conversion error: {e}")
# Different handlers for different exceptions
try:
f = open("nonexistent.txt")
data = f.read()
except FileNotFoundError:
print("File not found")
except PermissionError:
print("No permission")
except Exception as e:
print(f"Unexpected: {e}")
else:
print("No exception occurred")
f.close()
finally:
print("Cleanup (always runs)")
# Exception hierarchy
# BaseException
# ├── SystemExit
# ├── KeyboardInterrupt
# └── Exception
# ├── ValueError
# ├── TypeError
# ├── KeyError
# └── ...例外の送出
raise を使用して例外を送出します。単独の 'raise' は現在の例外を再送出します(except ブロック内)。'raise X from Y' は例外をチェーンし、元の原因を保持します。常に具体的な例外型を送出してください。通常の制御フローに例外を使用するのは避けてください。
# Raise an exception
def divide(a, b):
if b == 0:
raise ZeroDivisionError("Cannot divide by zero!")
return a / b
# Re-raise the current exception
def process(data):
try:
return parse(data)
except ValueError:
print("Logging parse error...")
raise # re-raises the same exception
# Raise with context (from)
try:
int("abc")
except ValueError as e:
raise RuntimeError("Failed to process input") from e
# Common built-in exceptions
raise ValueError("invalid value")
raise TypeError("wrong type")
raise KeyError("missing key")
raise IndexError("out of range")
raise RuntimeError("something went wrong")
raise NotImplementedError("override this")
raise FileNotFoundError("no such file")
# Exception with custom args
class ValidationError(Exception):
pass
raise ValidationError("field is required", "email")カスタム例外
Exception(またはより具体的な組み込み例外)をサブクラス化してカスタム例外を作成します。呼び出し元が適切なレベルでキャッチできるよう、階層を設計してください。コンテキストを伝えるためにカスタム属性を追加します。BaseException(SystemExit/KeyboardInterrupt を含む)ではなく Exception から継承してください。
# Custom exception hierarchy
class AppError(Exception):
"""Base exception for the application."""
pass
class DatabaseError(AppError):
def __init__(self, message, query=None):
super().__init__(message)
self.query = query
class ValidationError(AppError):
def __init__(self, field, message):
super().__init__(f"{field}: {message}")
self.field = field
self.message = message
class AuthenticationError(AppError):
pass
# Usage
def login(username, password):
if not username:
raise ValidationError("username", "is required")
if password != "secret":
raise AuthenticationError("Invalid credentials")
# Catching by hierarchy
try:
login("", "x")
except ValidationError as e:
print(f"Validation failed: {e.field}")
except AppError as e:
print(f"App error: {e}")
# Access exception info
import traceback
try:
1 / 0
except:
traceback.print_exc()
print(repr(sys.exc_info()[1]))コンテキストマネージャ(with 文)
コンテキストマネージャ('with' 文)は __enter__ と __exit__ によりクリーンアップを保証します。ファイル、ロック、データベース接続などのリソースに不可欠です。contextlib.contextmanager はジェネレータを使用して作成を簡素化します。__exit__ は True を返すことで例外を抑制できます。
# Context managers handle setup and cleanup
with open("file.txt") as f:
content = f.read()
# file is automatically closed, even if an error occurs
# Multiple context managers
with open("input.txt") as fin, open("output.txt", "w") as fout:
fout.write(fin.read())
# Creating a context manager (class-based)
class Timer:
def __enter__(self):
import time
self.start = time.time()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
import time
self.elapsed = time.time() - self.start
print(f"Elapsed: {self.elapsed:.4f}s")
return False # don't suppress exceptions
with Timer() as t:
# code to time
sum(range(1000000))
# contextlib for simpler context managers
from contextlib import contextmanager
@contextmanager
def open_db(url):
db = connect(url)
try:
yield db
finally:
db.close()
with open_db("localhost") as db:
db.query("SELECT 1")アサーションとロギング
assert 文は不変条件のデバッグ用です — Python を -O(最適化)で実行すると削除されます。入力検証にアサーションを使用しないでください。本番コードでは print() の代わりに logging モジュールを使用してください — レベル、フォーマット、出力先をサポートします。
# Assertions - for debugging (removed with -O flag)
def divide(a, b):
assert b != 0, "Divisor cannot be zero"
return a / b
# Never use assertions for data validation (they can be disabled)
# Use them for invariant checks during development
# Logging (better than print for production)
import logging
# Configure logging
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s [%(levelname)s] %(message)s"
)
logger = logging.getLogger(__name__)
logger.debug("Detailed info for debugging")
logger.info("Confirmation things are working")
logger.warning("Something unexpected happened")
logger.error("A serious problem")
logger.critical("A fatal error")
# Log exceptions with traceback
try:
1 / 0
except:
logger.exception("Failed to divide") # includes tracebackファイル I/O
ファイルの読み込み
ファイルを開く際は常に 'with' を使用してください — エラーが発生しても自動的に閉じます。プラットフォーム依存のエンコーディング問題を回避するため encoding='utf-8' を指定してください。大きなファイルでは、メモリを節約するために read() ではなく行ごとに反復してください。readlines() はファイル全体をメモリに読み込みます。
# Read entire file
with open("file.txt", "r", encoding="utf-8") as f:
content = f.read()
print(content)
# Read line by line (memory-efficient for large files)
with open("file.txt", "r") as f:
for line in f:
print(line.strip()) # strip removes trailing newline
# Read all lines into a list
with open("file.txt") as f:
lines = f.readlines() # ['line1\n', 'line2\n', ...]
# Read specific number of characters
with open("file.txt") as f:
chunk = f.read(100) # first 100 chars
# File modes:
# "r" read (default)
# "w" write (truncate)
# "a" append
# "x" exclusive create (fails if exists)
# "b" binary mode (e.g., "rb", "wb")
# "+" read and write (e.g., "r+")ファイルの書き込み
モード 'w' はファイルを切り詰めます(内容を削除);追記には 'a' を使用してください。writelines() は改行を追加しません — 手動で追加してください。バイナリファイル(画像など)には 'rb'/'wb' を使用してください。seek() はカーソルを移動し、tell() は位置を返します。テキストファイルには常にエンコーディングを指定してください。
# Write text (overwrites existing)
with open("output.txt", "w") as f:
f.write("First line\n")
f.write("Second line\n")
# writelines doesn't add newlines
f.writelines(["line3\n", "line4\n"])
# Append to a file
with open("log.txt", "a") as f:
f.write("New log entry\n")
# Write binary data
with open("data.bin", "wb") as f:
f.write(b"\x00\x01\x02\x03")
# Read and write simultaneously
with open("file.txt", "r+") as f:
content = f.read()
f.seek(0) # move to beginning
f.write("Updated") # overwrite
f.truncate() # cut off remaining
# Check if file exists
import os
if os.path.exists("file.txt"):
print("File exists")パス処理(pathlib)
pathlib(Python 3.4+)はモダンなオブジェクト指向のパス処理方法です — os.path より優先してください。/ 演算子はプラットフォームに依存せずパスを結合します。Path オブジェクトには open/close を処理する read_text()/write_text() メソッドがあります。rglob() は再帰的に検索します。
from pathlib import Path
# Create Path objects (preferred over os.path)
p = Path("src/main.py")
home = Path.home() # /home/user or C:\Users\user
cwd = Path.cwd() # current working directory
# Path components
print(p.name) # main.py
print(p.stem) # main
print(p.suffix) # .py
print(p.parent) # src
print(p.parts) # ('src', 'main.py')
# Joining paths (use / operator)
config = home / ".config" / "app" / "config.json"
# Existence and type
print(p.exists()) # True/False
print(p.is_file())
print(p.is_dir())
# Listing directories
for f in Path(".").iterdir():
print(f)
# Glob patterns
for py_file in Path(".").rglob("*.py"):
print(py_file)
# Create directories
Path("new/dir").mkdir(parents=True, exist_ok=True)
# Read/write (Path methods)
content = Path("file.txt").read_text()
Path("output.txt").write_text("Hello!")JSON
json.dumps() は文字列にシリアライズし、json.loads() はデシリアライズします。dump()/load() はファイルを扱います。pretty-printing には indent を使用してください。カスタムオブジェクトにはデフォルトシリアライザが必要です。JSON は基本型のみサポートします — datetime やその他の複雑なオブジェクトには default= を使用してください。
import json
# Python dict to JSON string
data = {"name": "Alice", "age": 30, "skills": ["Python", "SQL"]}
json_str = json.dumps(data, indent=2)
print(json_str)
# JSON string to Python dict
parsed = json.loads('{"name": "Bob", "active": true}')
print(parsed["name"]) # Bob
print(parsed["active"]) # True (Python bool)
# Write JSON to file
with open("data.json", "w") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
# Read JSON from file
with open("data.json") as f:
loaded = json.load(f)
# Custom serialization (e.g., datetime)
from datetime import datetime
def json_default(obj):
if isinstance(obj, datetime):
return obj.isoformat()
raise TypeError
json.dumps({"time": datetime.now()}, default=json_default)
# Type mapping:
# JSON object <-> Python dict
# JSON array <-> Python list
# JSON string <-> Python str
# JSON number <-> Python int/float
# JSON boolean <-> Python bool
# JSON null <-> Python NoneCSV とその他のフォーマット
csv モジュールは適切な引用符付きで CSV を処理します。Windows で CSV ファイルを開く際は newline='' を使用してください。DictReader/DictWriter は列名で動作します。pickle は任意の Python オブジェクトをシリアライズできますが、Python 固有で安全ではありません — 信頼できないソースからのデータを unpickle しないでください。
import csv
# Write CSV
with open("data.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["name", "age", "city"])
writer.writerows([
["Alice", 30, "NYC"],
["Bob", 25, "LA"],
])
# Read CSV
with open("data.csv") as f:
reader = csv.reader(f)
header = next(reader) # first row
for row in reader:
print(row) # ['Alice', '30', 'NYC']
# DictReader/DictWriter (column access by name)
with open("data.csv") as f:
reader = csv.DictReader(f)
for row in reader:
print(row["name"], row["age"])
# Pickle (Python-specific, can store any object)
import pickle
with open("data.pkl", "wb") as f:
pickle.dump({"complex": [1, 2, {"a": 3}]}, f)
with open("data.pkl", "rb") as f:
obj = pickle.load(f)
# WARNING: pickle is insecure - never unpickle untrusted data!モジュールとパッケージ
モジュールのインポート
インポートはモジュールを取り込みます。'import X' は名前空間をクリーンに保ちます。'from X import Y' は便利ですが、名前の衝突を起こす可能性があります。エイリアス(import X as Y)は慣習のあるライブラリ(np、pd)で一般的です。'from X import *' は避けてください — 名前空間を汚染します。
# Import entire module
import math
print(math.sqrt(16))
# Import specific names
from datetime import datetime, timedelta
now = datetime.now()
# Import with alias
import numpy as np
import pandas as pd
# Import all names (discouraged - pollutes namespace)
# from os import *
# Conditional import (try/except)
try:
import cjson as json
except ImportError:
import json
# Check what's in a module
import os
print(dir(os)) # list all attributes
print(os.__file__) # module location
print(os.__name__) # module name
# Reload a module (during development)
import importlib
importlib.reload(my_module)モジュールとパッケージの作成
モジュールは .py ファイルです;パッケージは __init__.py を含むディレクトリです。__init__.py ファイルは空でもパッケージをセットアップしてもかまいません。__init__.py の __all__ は 'from package import *' がエクスポートするものを制御します。モダンな Python(3.3+)は __init__.py なしで名前空間パッケージをサポートします。
# A module is just a .py file
# mymath.py
def add(a, b):
return a + b
PI = 3.14159
# A package is a directory with __init__.py
# mypackage/
# __init__.py
# module1.py
# module2.py
# subpackage/
# __init__.py
# module3.py
# __init__.py can be empty or contain package initialization
# mypackage/__init__.py
from .module1 import ClassA
from .module2 import func_b
__version__ = "1.0.0"
__all__ = ["ClassA", "func_b"]
# Using the package
from mypackage import ClassA
from mypackage.subpackage import module3
# __all__ controls 'from package import *'
# Without __all__, * imports only what's in __init__.py__name__ == '__main__'
if __name__ == '__main__' のイディオムにより、ファイルはスクリプトとモジュールの両方として機能できます。直接実行すると __name__ は '__main__' になり、インポート時はモジュール名になります。このパターンは、単独で実行できる再利用可能なモジュールを作るために不可欠です。
# script.py
def main():
print("Running main")
def helper():
print("Helper function")
if __name__ == "__main__":
# This code only runs when the file is executed directly
# NOT when imported as a module
main()
# When you run: python script.py
# __name__ is "__main__" -> main() runs
# When you: import script
# __name__ is "script" -> main() does NOT run
# This lets the module be both a script and an importable library
# Common pattern for CLI tools
def main():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--name", required=True)
args = parser.parse_args()
print(f"Hello, {args.name}!")
if __name__ == "__main__":
main()標準ライブラリのハイライト
Python の標準ライブラリは巨大でバッテリー同梱です。システム連携には os/sys、日付には datetime、特殊コンテナには collections、イテレータツールには itertools、関数型プログラミングには functools。docs.python.org/3/library/ でドキュメントを探索してください。
# os - operating system interface
import os
os.getcwd() # current directory
os.listdir(".") # list files
os.environ.get("HOME") # environment variables
# sys - system-specific
import sys
sys.argv # command-line arguments
sys.exit(0) # exit with status code
sys.path # module search path
# datetime - date and time
from datetime import datetime, timedelta
now = datetime.now()
# collections - specialized containers
from collections import Counter, defaultdict, deque
# itertools - iterator tools
from itertools import chain, cycle, repeat, product
# functools - higher-order functions
from functools import lru_cache, reduce, partial
# typing - type hints
from typing import List, Dict, Optional, Union, Any
# pathlib - path handling
from pathlib import Path
# subprocess - run external commands
import subprocess
result = subprocess.run(["ls", "-l"], capture_output=True, text=True)Pip と仮想環境
プロジェクトの依存関係を分離するために、常に仮想環境を使用してください。venv は組み込みです;代替には virtualenv、conda、uv があります。再現性のために requirements.txt でバージョンを固定してください。--user や root としてグローバルにパッケージをインストールしないでください — venv を使用してください。
# Create a virtual environment
# $ python -m venv venv
# Activate it
# Windows: venv\Scripts\activate
# Unix: source venv/bin/activate
# Install packages
# $ pip install requests
# $ pip install requests==2.28.0
# $ pip install "requests>=2.25,<3.0"
# Install from requirements file
# $ pip install -r requirements.txt
# requirements.txt example:
# requests==2.31.0
# numpy>=1.21.0
# pandas~=2.0.0 # compatible release
# List installed packages
# $ pip list
# $ pip freeze > requirements.txt
# Uninstall
# $ pip uninstall requests
# Show package info
# $ pip show requests
# Modern alternative: uv (faster)
# $ uv pip install requests日付と時刻
datetime モジュール
datetime モジュールは date、time、datetime、timedelta クラスを提供します。datetime.now() はローカル時刻を返します;UTC には datetime.now(timezone.utc) を使用してください。weekday() は 0-6(月-日)を返します。本番環境では曖昧さを回避するため、常にタイムゾーン対応の datetime を使用してください。
from datetime import datetime, date, time, timedelta
# Current date and time
now = datetime.now() # local time
utc_now = datetime.utcnow() # UTC (deprecated in 3.12)
utc = datetime.now(timezone.utc) # preferred
# Current date
today = date.today()
# Create specific date/time
dt = datetime(2024, 1, 15, 10, 30, 0)
d = date(2024, 1, 15)
t = time(10, 30, 0)
# Access components
print(now.year, now.month, now.day)
print(now.hour, now.minute, now.second)
print(now.weekday()) # 0=Monday, 6=Sunday
# From timestamp
ts = 1705315200
dt = datetime.fromtimestamp(ts)
# To timestamp
print(datetime.now().timestamp())フォーマットと解析
strftime(string format time)は datetime を文字列に変換し、strptime(string parse time)は文字列を datetime に変換します。ISO 8601 フォーマット(isoformat/fromisoformat)は日付を保存する最適な選択です — 曖昧さがなくソート可能です。一般的なコードを覚えてください:%Y %m %d %H %M %S。
from datetime import datetime
# Format datetime to string (strftime)
dt = datetime(2024, 1, 15, 10, 30)
print(dt.strftime("%Y-%m-%d")) # 2024-01-15
print(dt.strftime("%Y/%m/%d %H:%M")) # 2024/01/15 10:30
print(dt.strftime("%B %d, %Y")) # January 15, 2024
print(dt.strftime("%A")) # Monday
# Parse string to datetime (strptime)
dt = datetime.strptime("2024-01-15", "%Y-%m-%d")
dt = datetime.strptime("15/01/2024 10:30", "%d/%m/%Y %H:%M")
# Common format codes:
# %Y year (2024) %m month (01)
# %d day (15) %H hour (14)
# %M minute (30) %S second (00)
# %B month name %b month abbrev
# %A weekday name %a weekday abbrev
# %I 12-hour %p AM/PM
# %j day of year %U week number
# ISO format (recommended for storage)
iso = dt.isoformat() # "2024-01-15T10:30:00"
dt = datetime.fromisoformat("2024-01-15T10:30:00")timedelta と算術
timedelta は期間を表します。datetime に timedelta を加算/減算でき、2 つの datetime を減算して timedelta を得られます。timedelta は正規化します:days=1, hours=25 は days=2, hours=1 になります。total_seconds() は期間全体を秒で返します。
from datetime import datetime, timedelta
now = datetime.now()
# Add/subtract time
tomorrow = now + timedelta(days=1)
last_week = now - timedelta(weeks=1)
in_2_hours = now + timedelta(hours=2)
in_90_days = now + timedelta(days=90)
# Difference between dates
date1 = datetime(2024, 1, 15)
date2 = datetime(2024, 6, 18)
diff = date2 - date1
print(diff.days) # 155
print(diff.total_seconds())
# timedelta components
td = timedelta(days=5, hours=3, minutes=30)
print(td.days) # 5
print(td.seconds) # 12600 (3h 30m in seconds)
print(td.total_seconds())
# Comparisons
if now > date1:
print("now is later")
# Business day calculation (using numpy)
# import numpy as np
# business_days = np.busday_count(date1.date(), date2.date())タイムゾーン
常にタイムゾーン対応の datetime を使用してください(Python 3.9+ では pytz より ZoneInfo が推奨されます)。日付は UTC で保存し、表示用にのみローカル時刻に変換してください。ナイーブな datetime(tzinfo なし)は微妙なバグを引き起こします。ZoneInfo は IANA タイムゾーンデータベースを使用し、DST を自動的に処理します。
from datetime import datetime, timezone, timedelta
# Timezone-aware datetime
utc_time = datetime.now(timezone.utc)
print(utc_time) # 2024-01-15 10:30:00+00:00
# Create a timezone (offset-based)
tz_ny = timezone(timedelta(hours=-5), "EST")
ny_time = datetime.now(tz_ny)
# Convert between timezones
utc_time = datetime.now(timezone.utc)
ny_time = utc_time.astimezone(timezone(timedelta(hours=-5)))
tokyo_time = utc_time.astimezone(timezone(timedelta(hours=9)))
# Use zoneinfo (Python 3.9+) for IANA timezones
from zoneinfo import ZoneInfo
tz = ZoneInfo("America/New_York")
dt = datetime.now(tz)
print(dt.tzname()) # EST or EDT
# Common IANA timezones:
# "UTC"
# "America/New_York", "America/Los_Angeles"
# "Europe/London", "Europe/Paris"
# "Asia/Tokyo", "Asia/Shanghai"
# "Australia/Sydney"
# Best practice: store UTC, convert for display
utc_stored = datetime.now(timezone.utc)
local_display = utc_stored.astimezone(ZoneInfo("Asia/Shanghai"))正規表現
re モジュールの基礎
re.search() は任意の場所で最初のマッチを見つけます;re.match() は先頭のみ;re.fullmatch() は文字列全体がマッチする必要があります。バックスラッシュエスケープの問題を回避するため、パターンには raw 文字列(r'...')を使用してください。Match オブジェクトは group()、start()、end()、span() を提供します。
import re
# re.search - find first match anywhere in string
m = re.search(r"\d{4}", "Order #2024 was placed")
if m:
print(m.group()) # 2024
print(m.start(), m.end()) # 9 13
# re.match - match at beginning of string
m = re.match(r"Hello", "Hello, World")
print(m.group()) # Hello
# re.fullmatch - entire string must match
m = re.fullmatch(r"\d+", "12345")
print(bool(m)) # True
# re.findall - all matches as list
emails = re.findall(r"\S+@\S+", text)
numbers = re.findall(r"\d+", "a1b22c333") # ['1', '22', '333']
# re.finditer - all matches as iterator (with positions)
for m in re.finditer(r"\w+", "Hello World"):
print(m.group(), m.span())
# Match object methods
m = re.search(r"(\w+)@(\w+)", "[email protected]")
print(m.group()) # user@domain (whole match)
print(m.group(1)) # user (first group)
print(m.group(2)) # domain (second group)
print(m.groups()) # ('user', 'domain')パターン構文
正規表現構文:文字クラスには []、一般的なセットには \d \w \s、繰り返しには量指定子(* + ? {})、アンカーには ^ $ \b、グループには ()、選択には |。バックスラッシュを文字通りにするため raw 文字列(r'...')を使用してください。貪欲な量指定子は可能な限りマッチします;遅延にするには ? を追加(例:*?)。
import re
# Character classes
re.findall(r"[aeiou]", "hello") # vowels
re.findall(r"[^aeiou]", "hello") # non-vowels
re.findall(r"[a-z]", "Hello123") # lowercase
re.findall(r"[A-Za-z0-9]", "Hi-1!") # alphanumeric
# Predefined classes
# . any char except newline
# \d digit [0-9] \D non-digit
# \w word char [a-zA-Z0-9_] \W non-word
# \s whitespace \S non-whitespace
# Quantifiers
# * 0 or more
# + 1 or more
# ? 0 or 1
# {n} exactly n
# {n,} n or more
# {n,m} between n and m
re.findall(r"\d{3}", "1234567") # ['123', '456']
re.findall(r"\d{2,4}", "12345678") # ['1234', '5678']
# Anchors
# ^ start of string $ end of string
# \b word boundary
re.findall(r"^\w+", "Hello World") # ['Hello']
re.findall(r"\b\w+\b", "hi there") # ['hi', 'there']
# Groups & alternation
re.findall(r"(cat|dog)", "cat and dog") # ['cat', 'dog']
re.findall(r"(\w+)@(\w+\.\w+)", "[email protected]")置換と分割
re.sub() はマッチを置換します — グループを参照するには後方参照(\1、\2)を、動的置換には関数を使用してください。re.split() は str.split() より強力です — 正規表現パターンを受け入れます。パターン内のキャプチャグループは結果に含まれます。(result, count) を得るには re.subn() を使用してください。
import re
# re.sub - replace matches
result = re.sub(r"\d+", "#", "a1b22c333")
# 'a#b#c#'
# Replace with count limit
result = re.sub(r"\d", "X", "a1b2c3", count=2)
# 'aXbXc3'
# Use backreferences in replacement
result = re.sub(r"(\w+)@(\w+)", r"\2.\1", "user@domain")
# 'domain.user'
# Use function as replacement
def upper(m):
return m.group().upper()
result = re.sub(r"\b[a-z]", upper, "hello world")
# 'Hello World' (capitalize first letter of each word)
# re.split - split by pattern
parts = re.split(r"[,;\s]+", "a, b; c d")
# ['a', 'b', 'c', 'd']
# Split with capture groups (keeps delimiters)
parts = re.split(r"([,;])", "a,b;c")
# ['a', ',', 'b', ';', 'c']
# Split with maxsplit
parts = re.split(r",", "a,b,c,d", maxsplit=2)
# ['a', 'b', 'c,d']コンパイルとフラグ
パターンを繰り返し使用する場合は re.compile() でコンパイルしてください — より高速です。フラグは動作を変更します:IGNORECASE、MULTILINE、DOTALL、VERBOSE(パターン内のコメント/空白を許可)。名前付きグループ (?P<name>...) は可読性を向上させます。先読み (?=) と後読み (?<=) は消費せずにマッチします。
import re
# Compile pattern for reuse (faster when used many times)
email_re = re.compile(r"^[\w.+-]+@([\w-]+\.)+[\w-]+$")
print(email_re.match("[email protected]")) # match object
print(email_re.match("invalid")) # None
# Common flags
re.IGNORECASE # case-insensitive
re.MULTILINE # ^ and $ match line boundaries
re.DOTALL # . matches newline too
re.VERBOSE # allow whitespace & comments in pattern
# Combine flags with |
pattern = re.compile(r"""
^ # start of line
(\w+) # capture word
\s+ # whitespace
(\d+) # capture number
""", re.VERBOSE | re.MULTILINE)
# Named groups (more readable)
m = re.match(r"(?P<year>\d{4})-(?P<month>\d{2})", "2024-01")
print(m.group("year")) # 2024
print(m.group("month")) # 01
print(m.groupdict()) # {'year': '2024', 'month': '01'}
# Lookahead/lookbehind
re.findall(r"\d+(?= dollars)", "100 dollars, 200 euros")
# ['100'] (positive lookahead)
re.findall(r"(?<=\$)\d+", "$100 and $200")
# ['100', '200'] (positive lookbehind)非同期と並行処理
asyncio の基礎
asyncio は Python の非同期 I/O フレームワークです。'async def' はコルーチンを定義し、'await' は結果が ready になるまで中断します。asyncio.run() はイベントループを開始します。asyncio.gather() はコルーチンを並行実行します。コルーチンにより、スレッドなしで高並行 I/O が可能になります。
import asyncio
# Define a coroutine
async def greet(name, delay):
await asyncio.sleep(delay) # non-blocking sleep
return f"Hello, {name}!"
# Run a coroutine
async def main():
result = await greet("Alice", 1)
print(result)
# Run the event loop
asyncio.run(main())
# Concurrent execution with gather
async def main():
# Run coroutines concurrently
results = await asyncio.gather(
greet("Alice", 2),
greet("Bob", 1),
greet("Carol", 3)
)
print(results) # all complete after 3 seconds (max delay)
asyncio.run(main())
# asyncio.create_task - schedule without awaiting immediately
async def main():
task = asyncio.create_task(greet("Alice", 1))
# do other work here
result = await task # await when needed
print(result)非同期 HTTP とタイムアウト
asyncio.timeout()(Python 3.11+)は時間のかかる操作をキャンセルします。HTTP には requests(同期)の代わりに aiohttp(非同期)を使用してください。asyncio.Queue はプロデューサー・コンシューマパターンを可能にします。非同期は I/O バウンドの作業(ネットワーク、ディスク)に理想的です — CPU バウンドの作業には適しません。
import asyncio
# Async timeout
async def fetch_with_timeout(url, timeout=5):
try:
async with asyncio.timeout(timeout):
# simulate async operation
await asyncio.sleep(2)
return f"Data from {url}"
except asyncio.TimeoutError:
return "Request timed out"
# Using aiohttp (third-party) for HTTP
# import aiohttp
#
# async def fetch(url):
# async with aiohttp.ClientSession() as session:
# async with session.get(url) as response:
# return await response.text()
# Producer-consumer pattern
async def producer(queue):
for i in range(5):
await asyncio.sleep(0.1)
await queue.put(f"item-{i}")
await queue.put(None) # sentinel
async def consumer(queue):
while True:
item = await queue.get()
if item is None:
break
print(f"Processed: {item}")
queue.task_done()
async def main():
queue = asyncio.Queue()
await asyncio.gather(producer(queue), consumer(queue))
asyncio.run(main())スレッド
スレッドは I/O バウンドの並行処理(ネットワーク、ファイル I/O)用です。Python の GIL により、スレッドでの真の並列 CPU 実行は防止されます。共有状態を競合状態から保護するには Lock を使用してください。CPU バウンドの作業には multiprocessing を使用してください。スレッドはメモリを共有します;プロセスは共有しません。
import threading
import time
# Basic threading
def worker(name, delay):
print(f"Worker {name} starting")
time.sleep(delay)
print(f"Worker {name} done")
# Create and start threads
t1 = threading.Thread(target=worker, args=("A", 2))
t2 = threading.Thread(target=worker, args=("B", 1))
t1.start()
t2.start()
# Wait for threads to complete
t1.join()
t2.join()
print("All done")
# Thread with Lock (for shared state)
counter = 0
lock = threading.Lock()
def increment():
global counter
for _ in range(100000):
with lock: # acquire/release lock
counter += 1
threads = [threading.Thread(target=increment) for _ in range(5)]
for t in threads: t.start()
for t in threads: t.join()
print(f"Counter: {counter}") # 500000 (correct with lock)マルチプロセス
マルチプロセスは GIL をバイパスして真の CPU 並列処理を行います — 各プロセスには独自の Python インタープリタがあります。並列 map 操作には Pool を使用してください。concurrent.futures はスレッドとプロセスの両方に統一された API を提供します。Windows では常に if __name__ == '__main__' でガードしてください。
from multiprocessing import Process, Pool, Queue
import os
# Basic process
def worker(name):
print(f"Process {name} PID: {os.getpid()}")
if __name__ == "__main__":
p = Process(target=worker, args=("A",))
p.start()
p.join()
# Process pool for parallel work
def square(x):
return x * x
if __name__ == "__main__":
with Pool(4) as pool: # 4 worker processes
results = pool.map(square, range(10))
print(results) # [0, 1, 4, 9, ..., 81]
# Asynchronous map
with Pool(4) as pool:
result = pool.map_async(square, range(10))
print(result.get()) # blocks until done
# concurrent.futures (higher-level API)
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
with ProcessPoolExecutor() as executor:
results = list(executor.map(square, range(10)))
with ThreadPoolExecutor() as executor:
futures = [executor.submit(square, i) for i in range(10)]
results = [f.result() for f in futures]デコレータ
基本的なデコレータ
デコレータは元のソースを変更せずに、関数をラップして振る舞いを拡張または変更します。@構文はデコレータ呼び出しの結果を関数名に再代入する糖衣構文です。任意のシグネチャで動作するよう、ラッパーで *args、**kwargs を使用してください。
# A decorator is a function that takes a function and returns a new function
def uppercase_result(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result.upper()
return wrapper
@uppercase_result
def greet(name):
return f"hello, {name}"
print(greet("world")) # HELLO, WORLD
# @uppercase_result is sugar for: greet = uppercase_result(greet)functools.wraps(メタデータの保持)
@wraps がないと、ラップされた関数は元の __name__、__doc__、シグネチャを失います — デバッグツールや help() は 'wrapper' と表示します。メタデータを保持するため、デコレータ内で常に @functools.wraps(func) を使用してください。これはほぼ普遍的なベストプラクティスです。
from functools import wraps
def log_calls(func):
@wraps(func) # copies __name__, __doc__, __module__
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}({args}, {kwargs})")
return func(*args, **kwargs)
return wrapper
@log_calls
def add(a, b):
"""Add two numbers."""
return a + b
print(add.__name__) # 'add' (not 'wrapper')
print(add.__doc__) # 'Add two numbers.'
help(add) # shows original docstring引数付きデコレータ
デコレータが引数を取る場合、3 レベルのネストが必要です:ファクトリ(引数を取る)、デコレータ(関数を取る)、ラッパー(呼び出し引数を取る)。@repeat(3) はまず repeat(3) を呼び出し、デコレータを返し、それが関数に適用されます。
# A decorator factory: returns the actual decorator
def repeat(times):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
result = None
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(times=3)
def say_hi(name):
print(f"Hi, {name}!")
say_hi("Alice")
# Hi, Alice! (printed 3 times)クラスベースのデコレータ
クラスデコレータは __init__ で関数を格納し、__call__ で呼び出しをインターセプトします。デコレータが状態(呼び出しカウンタやキャッシュなど)を維持する必要がある場合に理想的です。クラスインスタンスが関数を置き換え るため、呼び出すと __call__ がトリガーされます。
class CountCalls:
def __init__(self, func):
self.func = func
self.count = 0
wraps(func)(self) # preserve metadata
def __call__(self, *args, **kwargs):
self.count += 1
print(f"{self.func.__name__} called {self.count} times")
return self.func(*args, **kwargs)
@CountCalls
def say_hello():
print("Hello!")
say_hello() # count=1
say_hello() # count=2
say_hello() # count=3
print(say_hello.count) # 3組み込みデコレータ(@property、@staticmethod、@classmethod)
@property はメソッドを計算済み属性に変えます(括弧なしでアクセス)。@classmethod は第一引数としてクラスを受け取ります — 代替コンストラクタに最適です。@staticmethod は暗黙の第一引数を受け取りません — たまたまクラス名前空間にある関数です。これらが組み合わさって Pythonic な OOP の骨格を形成します。
class Circle:
pi = 3.14159
def __init__(self, radius):
self._radius = radius
@property
def area(self):
return Circle.pi * self._radius ** 2
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value < 0:
raise ValueError("Radius cannot be negative")
self._radius = value
@classmethod
def from_diameter(cls, diameter):
return cls(diameter / 2)
@staticmethod
def is_valid_radius(r):
return r >= 0
c = Circle(5)
print(c.area) # 78.54 (no parentheses!)
c.radius = 10 # uses the setter
c2 = Circle.from_diameter(20) # alternative constructorスタックされたデコレータ
デコレータをスタックする場合、ボトムアップで適用され(関数に最も近いものが最初に実行)、呼び出し時にはトップダウンで実行されます。つまり @bold が @italic が greet をラップします。結果は玉ねぎの層のようにネストされます。順序は重要です — 逆にすると出力のネストが変わります。
from functools import wraps
def bold(func):
@wraps(func)
def wrapper(*args, **kwargs):
return f"<b>{func(*args, **kwargs)}</b>"
return wrapper
def italic(func):
@wraps(func)
def wrapper(*args, **kwargs):
return f"<i>{func(*args, **kwargs)}</i>"
return wrapper
@bold
@italic
def greet(name):
return f"Hello, {name}"
print(greet("World"))
# <b><i>Hello, World</i></b>
# Applied bottom-up: italic first, then bold