Python入門

初心者がやりがちな5つのアンチパターン!コードが汚くなる原因を一気に解説

「コードは動いてるんだけど、なんか汚い気がする…」

そんなモヤモヤ、感じたことありませんか? 実は、初心者のうちに書いてしまいがちな「アンチパターン(悪い書き方のパターン)」がいくつかあって、知らないうちにそれをやってしまっている可能性が高いんです。

今回は、初心者がよくハマる 5つのアンチパターン を、Pythonコード例とともにわかりやすく解説します。「むずかしそう」を「できそう」に変えていきましょう! 🚀

🎯 対象読者

messy code refactoring
messy code refactoring / Photo by Daniil Komov via Pexels

Pythonを書き始めて間もない方、または「なんとなく動くけど自信がない」という初〜中級者の方にぴったりの内容です。この記事を読めば、コードレビューで指摘されやすいポイントを事前に把握できますよ。

❌ アンチパターン1:引数が多すぎる関数

関数に引数をどんどん追加していくと、こんなことになりがちです。

# ❌ 悪い例:引数が多すぎて何が何だかわからない
def create_user(name, age, email, country, city, role, is_active):
    pass

create_user("田中太郎", 25, "tanaka@example.com", "Japan", "Tokyo", "admin", True)
# → 呼び出し側を見ても、何番目が何の値かわからない!

引数が4つ以上になってきたら危険信号です。呼び出し側のコードを見たとき、True"admin" が何を意味しているのかパッと分かりません。

改善策:データクラスや辞書にまとめる

from dataclasses import dataclass

@dataclass
class UserParams:
    name: str
    age: int
    email: str
    country: str
    city: str
    role: str
    is_active: bool

def create_user(params: UserParams):
    pass

# 呼び出し側が格段に読みやすくなる!
params = UserParams(
    name="田中太郎",
    age=25,
    email="tanaka@example.com",
    country="Japan",
    city="Tokyo",
    role="admin",
    is_active=True
)
create_user(params)

dataclass を使えば、引数をひとまとめにしつつ、型ヒントもついて一石二鳥です。

❌ アンチパターン2:意味のない変数名

「とりあえず動かしたい」という気持ちはわかりますが、変数名に axtmp を使いすぎると後で地獄を見ます。

# ❌ 悪い例:変数名が何を意味するか全くわからない
def calc(a, b, c):
    x = a * b
    y = x - c
    return y

result = calc(1200, 8, 500)
print(result)  # → 9100 … これは何??

改善策:変数名で「何を表しているか」を明示する

# ✅ 良い例:変数名を読むだけで処理が想像できる
def calc_monthly_profit(unit_price, quantity, fixed_cost):
    sales_amount = unit_price * quantity
    monthly_profit = sales_amount - fixed_cost
    return monthly_profit

profit = calc_monthly_profit(1200, 8, 500)
print(profit)  # → 9100(月次利益)

「3ヶ月後の自分が読んでもわかるか?」を基準に命名しましょう。コメントより先に、変数名で語れるコードが理想です。

❌ アンチパターン3:同じ処理をコピペしまくる(DRY原則違反)

「動いたからコピーして貼ればいいや」という発想は、バグの温床になります。

# ❌ 悪い例:同じような処理が至るところに散らばっている
print("=" * 30)
print("ユーザー情報")
print("=" * 30)

# ... 何十行か後 ...

print("=" * 30)
print("注文情報")
print("=" * 30)

# ... さらに後 ...

print("=" * 30)
print("配送情報")
print("=" * 30)

この状態で「区切り線を = から - に変えたい」となったら、全箇所を探して修正しなければなりません。修正漏れが起きると、それがバグになります。

改善策:共通処理を関数にまとめる(DRY原則)

# ✅ 良い例:1か所直すだけで全体に反映される
def print_section_header(title, width=30):
    print("-" * width)
    print(title)
    print("-" * width)

print_section_header("ユーザー情報")
print_section_header("注文情報")
print_section_header("配送情報")

DRY原則(Don’t Repeat Yourself)とは「同じことを繰り返すな」という考え方です。同じ処理が2回以上出てきたら、関数化を検討しましょう。

❌ アンチパターン4:何でもグローバル変数に入れる


「どこからでも使えるから便利!」とグローバル変数を多用すると、コードが大きくなるにつれて管理が破綻します。

# ❌ 悪い例:グローバル変数が乱用されている
user_name = ""
user_score = 0
user_level = 1

def login(name):
    global user_name
    user_name = name

def add_score(points):
    global user_score, user_level
    user_score += points
    if user_score >= 100:
        user_level += 1
        user_score = 0

login("太郎")
add_score(60)
add_score(50)
print(f"{user_name} / レベル{user_level}")

どの関数がグローバル変数を変更しているか追跡するのが大変になり、バグの原因を特定しづらくなります。

改善策:クラスや関数の引数・戻り値で状態を管理する

# ✅ 良い例:クラスで状態をひとまとめに管理する
class User:
    def __init__(self, name):
        self.name = name
        self.score = 0
        self.level = 1

    def add_score(self, points):
        self.score += points
        if self.score >= 100:
            self.level += 1
            self.score = 0

    def status(self):
        return f"{self.name} / レベル{self.level} / スコア{self.score}"

user = User("太郎")
user.add_score(60)
user.add_score(50)
print(user.status())  # 太郎 / レベル2 / スコア10

クラスを使うことで、状態の変更が user オブジェクトの中に閉じ込められ、追跡しやすくなります。

❌ アンチパターン5:例外をそのまま握りつぶす

エラーが出たとき、「とりあえず try-except で囲めばいいか」と例外を何も処理せずに握りつぶすのはとても危険です。

# ❌ 悪い例:例外を丸ごと無視している
def get_user_age(data, key):
    try:
        return data[key]
    except:
        pass  # 何も起きなかったように続行…

user_data = {"name": "花子", "age": 22}
age = get_user_age(user_data, "agee")  # キーのタイポ!
print(f"年齢:{age}")  # → 年齢:None(気づかないまま進んでしまう)

この書き方だと、エラーが起きても何も起きなかったように見えるため、バグの発見が大幅に遅れます。

改善策:例外の種類を特定し、適切に処理する

# ✅ 良い例:例外の種類を指定し、ログを残す or デフォルト値を返す
def get_user_age(data, key):
    try:
        return data[key]
    except KeyError:
        print(f"[警告] キー '{key}' が見つかりません。Noneを返します。")
        return None
    except TypeError:
        print("[エラー] dataが辞書ではありません。")
        raise

user_data = {"name": "花子", "age": 22}
age = get_user_age(user_data, "agee")
# → [警告] キー 'agee' が見つかりません。Noneを返します。

ポイントは3つです。

  • 例外の種類を絞るexcept:except Exception: で全部捕まえるのは避ける)
  • 何が起きたかをログに残すprint でも最低限OK)
  • どうしようもないエラーは raise で再送出する

📋 まとめ:5つのアンチパターン一覧

# アンチパターン 改善の方向性
1 引数が多すぎる関数 dataclassや辞書でまとめる
2 意味のない変数名 読めば意味がわかる名前にする
3 コピペの乱用(DRY違反) 共通処理を関数にまとめる
4 グローバル変数の多用 クラスや関数スコープで管理する
5 例外の握りつぶし 種類を特定して適切に処理する

どれも「動くから問題ない」と思いがちですが、コードは書いた後に読まれるものです。特にチーム開発や、数ヶ月後の自分が読み返すときに、このアンチパターンが積み重なっているとかなり苦労します。

🎉 おわりに


今回紹介した5つのアンチパターンは、どれも「知っているかどうか」だけの差です。完璧なコードを最初から書く必要はありません。まずは「あ、これやってたかも」と気づくことが第一歩です。

ぜひ自分の過去のコードを見返して、一つでも改善してみてください。それだけで、あなたのコードの質はぐっと上がりますよ 💪

📚 関連商品・おすすめ書籍

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

もしも

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

初心者に定番のPython入門書

Amazonで見る

実践Claude Code入門―現場で活用するためのAIコーディングの思考法

もしも

実践Claude Code入門―現場で活用するためのAIコーディングの思考法

AIコーディングの現場活用法を学ぶ一冊

Amazonで見る

Python Web開発実践入門 ―― FastAPIによるWebAPI開発と非同期処理

もしも

Python Web開発実践入門 ―― FastAPIによるWebAPI開発と非同期処理

FastAPIでWebAPI開発を実践的に学ぶ

Amazonで見る

※本記事にはアフィリエイトリンクが含まれます。

ABOUT ME
やまちゃん
これまで学生と社会人を合わせて5000人以上にプログラミング学習を指導。 ゼロからイチをわかりやすく解説する専門家として活動しており、本業ではArduinoを用いたIoT開発とロボットプログラミングが専門。 Pythonを用いたアプリ開発、ウェブアプリケーションの開発で業務の効率化をサポートしています。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です