0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

import * がよろしくないワケ「名前空間の汚染」をザックリ説明してみる

0
Last updated at Posted at 2026-07-31

import * でできること

例えば、標準ライブラリの一つ time 内にある sleeptime を使いたいとして、こんな感じに書くことができます。

from time import *

if __name__ == '__main__':
  print(time())  # 1785506340.7939897 - 実行時のシステム時間
  sleep(1)
  print(time())  # 1785506341.795028

ざっくり言うと、import * は「このファイル/ライブラリの中の全てをここに召喚して」という命令です。今のところはスッキリ書けていてよさそうに見えます。

ここでは Python を例に説明していますが、同様の import システムを持つ大抵のモダン言語において同様のことが言えます。

import * で困ること

time ライブラリだけでこの世の全てが片付くかというと、当然そうではありません。作ろうとするものによっては、pip での外部ライブラリや自作ライブラリなど、あらゆる import が増えていくわけです。

もし、そこでも import * を使い続けたとしたら?

from time import *
from sys import *
from os import *

from fastapi import *
from uvicorn import *

すると、作業場所からアクセス可能な関数やクラス、定数が膨大な量になってしまいます。

先の「このファイルの中の全てをここに召喚して」は、「この作業机にこの道具箱の中をすべてぶちまけて」ということでもあるのです。そんなことをしては、たちまち作業机は散らかって作業し辛くなってしまいます。これが 「名前空間の汚染」 と呼ばれます。

「物理の作業机じゃないから良いのでは?」「エディタの入力補完候補が多くなるだけで大したことないのでは?」と思われるかもしれません。

しかしこの問題は、作業のし辛さだけの問題ではありません。

もし仮に、あるファイルに time という関数があったとして・・・

my_lib.py
def time() -> str:
  return "hoge"

そして import * で標準ライブラリの time と、どっちも召喚すると?

from time import *
from my_lib import *

if __name__ == '__main__':
  print(time())  # hoge - 最初のサンプルと同じコードなのに結果が変わった!
  sleep(1)
  print(time())  # hoge

前に import した time が、後に import した自作ライブラリへサイレントに上書きされてしまうのです。

「自作関数に time なんて名前をつけるな!」というツッコミどころではありますが、ともかく import * をしている以上は 「サイレントに関数・クラス・定数が上書きされてしまうかもしれない」 という恐怖と隣り合わせになってしまいます。しかも Python 3.10.12 で試した限りは、ワーニングすら出てくれません。本当にサイレントです。

名前空間の汚染によって生じるこの弊害が、「名前の衝突」 と呼ばれます。

@gorn708 様のコメントを受けて - 2026/08/01 追記

より怖いのは、仮にパッケージが更新されて関数・クラス・定数が増えたとき。上の例で言うなら、新バージョンで time() が追加された、みたいなことがあった場合です。

コードを書いたそのときは time() 衝突が無くて大丈夫だったとしても、ライブラリをアップデートしたら突然おかしくなった、みたいなことがあり得ます。ある種、時限爆弾みたいな状態になるわけです。

ちなみに import * しまくった状況下は、アホほど大量のグローバル変数が宣言されているような状況と同等です。つまり、大量の使用済みの名前に怯えながら (=名前の衝突に怯えながら) 自作ロジックを書き進めることになるわけです。これもまた名前空間の汚染の弊害ですね。

他にも「依存関係が〜」といった話も挙げればキリがありませんが、本記事では割愛します。

モダンな言語の import の真髄

そこでモダン言語の import システムには、「必要なものだけ取り込む」機能というのがあるわけです。

from time import sleep, time

if __name__ == '__main__':
  print(time())
  sleep(1)
  print(time())

仮に、全く同じ名前の関数・定数が別のライブラリに存在していて、かつ両方とも使いたいなら・・・

import time
import my_lib

if __name__ == '__main__':
  print(time.time())    # 1785506957.6132894
  print(my_lib.time())  # hoge

または、python では as をつかって別の名前をつけて・・・

from time import time
from my_lib import time as my_time

if __name__ == '__main__':
  print(time())     # 1785507020.2397442
  print(my_time())  # hoge

これなら、サイレントに関数・定数が書き換えられてしまうことも避けられます。

ということで、「import * は特別な意図が無い限り使うな」と言われ、その理由は名前空間の汚染のためというお話でした。

コラム1: C/C++ #include の苦悩

さて、C/C++ を一度でも触れたことがある方は勘づいているかもしれません。そう、#include は強制で import * しかできない世界線です。

#include "stdio.h"

仮に printf() しか使わないとしても、stdio.h の全てを一旦受け入れる他ありません。scanf() にも fprintf() にも用事がなかったとしても、召喚する定めにあります。

では、他のライブラリと名前が絶対干渉しないようにするにはどうするかというと、独自のプレフィックスをつけるといった泥臭いことをするしかありません。

#define MYLIB_MACRO 0x01

int mylib_func1();
void mylib_func2();

作ろうとしているロジックに集中したいのに、他ライブラリの兼ね合いも含めて関数・クラス・変数名に気を配らないといけない。そんな不毛な悩みが古の言語故にあったわけです。それをモダンな言語では解消すべく、上のような import システムが作られた、と読み取れるわけですね。

コラム2: import * が許される例外

限られたシチュエーションにおいては、import * を使うのが公式的にも許されています。

標準ライブラリの ctypes がその一つです。以下の公式リファレンスでも import * をしているのが確認できます。

ctypes は、C または C互換の DLL とのインターフェースを提供するライブラリです。そして、C の int64double といった型を Python 上で扱うためのデータ型がたくさん定義されています。

ctypes data types

データ型を何個も指定して import をするのはちょっと手間です。

from ctypes import c_int, c_double

かといって ctypes. をいちいちつけるのも、読みやすさが落ちてしまい良くありません。

import ctypes

ctypes.c_int
ctypes.c_double

ところで、C の型を表現しているそれらは、どれも c_ で始まっています。これらは名前衝突も起き辛いと言えそうです。c_ 始まりでない、cdll といったものもありますが、これらも名前衝突はし辛そうです。(標準ライブラリという知名度抜群のポジションですし)

そういった利便性、リスクの低さから判断して、慣習的に ctypes もしくはいくつかの稀な例においては、import * が許されています。

0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?