6. モジュール¶
Python インタプリタを終了させ、再び起動すると、これまでに行ってきた定義 (関数や変数) は失われています。ですから、より長いプログラムを書きたいなら、テキストエディタを使ってインタプリタへの入力を用意しておき、手作業の代わりにファイルを入力に使って動作させるとよいでしょう。この作業を スクリプト (script) の作成と言います。プログラムが長くなるにつれ、メンテナンスを楽にするために、スクリプトをいくつかのファイルに分割したくなるかもしれません。また、いくつかのプログラムで書いてきた便利な関数について、その定義をコピーすることなく個々のプログラムで使いたいと思うかもしれません。
こういった要求をサポートするために、Python では定義をファイルに書いておき、スクリプトの中やインタプリタの対話インスタンス上で使う方法があります。このファイルを モジュール (module) と呼びます。モジュールにある定義は、他のモジュールや main モジュール (実行のトップレベルや電卓モードでアクセスできる変数の集まりを指します) に import (取り込み) することができます。
モジュールは Python の定義や文が入ったファイルです。ファイル名はモジュール名に接尾語 .py
がついたものになります。モジュールの中では、(文字列の) モジュール名をグローバル変数 __name__
で取得できます。例えば、お気に入りのテキストエディタを使って、現在のディレクトリに以下の内容のファイル fibo.py
を作成してみましょう:
# Fibonacci numbers module
def fib(n): # write Fibonacci series up to n
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
def fib2(n): # return Fibonacci series up to n
result = []
a, b = 0, 1
while a < n:
result.append(a)
a, b = b, a+b
return result
次に Python インタプリタに入り、モジュールを以下のコマンドで import しましょう:
>>> import fibo
この操作では、fibo
で定義された関数の名前を直接現在の namespace (詳細は Python のスコープと名前空間 を参照してください)に追加することはありません。単にモジュール名 fibo
だけを名前空間に追加します。関数にはモジュール名を使ってアクセスします:
>>> fibo.fib(1000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.fib2(100)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>> fibo.__name__
'fibo'
関数を度々使うのなら、ローカルな名前に代入できます:
>>> fib = fibo.fib
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
6.1. モジュールについてもうすこし¶
モジュールには、関数定義に加えて実行文を入れることができます。これらの実行文はモジュールを初期化するためのものです。これらの実行文は、インポート文の中で 最初に モジュール名が見つかったときにだけ実行されます。[1] (ファイルがスクリプトとして実行される場合も実行されます。)
各々のモジュールは、自分のプライベートな名前空間を持っていて、モジュールで定義されている関数はこのテーブルをグローバルな名前空間として使います。したがって、モジュールの作者は、ユーザのグローバル変数と偶然的な衝突が起こる心配をせずに、グローバルな変数をモジュールで使うことができます。一方、自分が行っている操作をきちんと理解していれば、モジュール内の関数を参照するのと同じ表記法 modname.itemname
で、モジュールのグローバル変数をいじることもできます。
モジュールは他のモジュールをインポートできます。 import
文はモジュール(さらに言えばスクリプトでも)の先頭に置きますが、これは慣習であって必須ではありません。インポートされたモジュール名は、モジュールのトップレベル(関数やクラスの外)に書いてあれば、モジュールのグローバルな名前空間に置かれます。
import
文には、あるモジュール内の名前を、import を実行しているモジュールの名前空間内に直接取り込むという変型があります。例えば:
>>> from fibo import fib, fib2
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
この操作は、import の対象となるモジュール名をローカルな名前空間内に取り入れることはありません (従って上の例では、 fibo
は定義されません)。
モジュールで定義されている名前を全て import するという変型もあります:
>>> from fibo import *
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
この書き方ではアンダースコア (_
) で始まるものを除いてすべての名前をインポートします。殆どの場面で、Python プログラマーはこの書き方を使いません。未知の名前がインタープリターに読み込まれ、定義済みの名前を上書きしてしまう可能性があるからです。
一般的には、モジュールやパッケージから *
を import するというやり方には賛同できません。というのは、この操作を行うとしばしば可読性に乏しいコードになるからです。しかし、対話セッションでキータイプの量を減らすために使うのは構わないでしょう。
モジュール名の後に as
が続いていた場合は、 as
の後ろの名前を直接、インポートされたモジュールが束縛します。
>>> import fibo as fib
>>> fib.fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
これは実質的には import fibo
と同じ方法でモジュールをインポートしていて、唯一の違いはインポートしたモジュールが fib
という名前で取り扱えるようになっていることです。
このインポート方法は from
が付いていても使え、同じ効果が得られます:
>>> from fibo import fib as fibonacci
>>> fibonacci(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
注釈
実行効率上の理由で、各モジュールはインタープリタの 1 セッションごとに 1 回だけ import されます。従って、モジュールを修正した場合には、インタープリタを再起動させなければなりません -- もしくは、その場で手直ししてテストしたいモジュールが 1 つだった場合には、例えば import importlib; importlib.reload(modulename)
のように importlib.reload()
を使ってください。
6.1.1. モジュールをスクリプトとして実行する¶
Python モジュールを
python fibo.py <arguments>
と実行すると、__name__
に __main__
が設定されている点を除いて import したときと同じようにモジュール内のコードが実行されます。つまりモジュールの末尾に:
if __name__ == "__main__":
import sys
fib(int(sys.argv[1]))
このコードを追加することで、このファイルが import できるモジュールであると同時にスクリプトとしても使えるようになります。なぜならモジュールが "main" ファイルとして起動されたときだけ、コマンドラインを解釈するコードが実行されるからです:
$ python fibo.py 50
0 1 1 2 3 5 8 13 21 34
モジュールが import された場合は、そのコードは実行されません:
>>> import fibo
>>>
この方法はモジュールに便利なユーザインターフェースを提供したり、テストのために (スクリプトをモジュールとして起動しテストスイートを実行して) 使われます。
6.1.2. モジュール検索パス¶
spam
という名前のモジュールをインポートするとき、インタープリタはまずその名前の組み込みモジュールを探します。モジュール名の一覧は sys.builtin_module_names
にあります。見つからなかった場合は、 spam.py
という名前のファイルを sys.path
にあるディレクトリのリストから探します。 sys.path
は以下の場所に初期化されます:
入力されたスクリプトのあるディレクトリ (あるいはファイルが指定されなかったときはカレントディレクトリ)。
PYTHONPATH
(ディレクトリ名のリスト。シェル変数のPATH
と同じ構文)。インストール方法に依存したデフォルト(慣例として
site-packages
ディレクトリーが含まれ、site
モジュールによって処理される)。
詳細は sys.path モジュール検索パスの初期化 を参照してください。
注釈
シンボリックリンクをサポートするファイルシステム上では、入力されたスクリプトのあるディレクトリはシンボリックリンクをたどった後に計算されます。言い換えるとシンボリックリンクを含むディレクトリはモジュール検索パスに追加 されません。
初期化された後、 Python プログラムは sys.path
を修正することができます。スクリプトファイルを含むディレクトリが検索パスの先頭、標準ライブラリパスよりも前に追加されます。なので、ライブラリのディレクトリにあるファイルよりも、そのディレクトリにある同じ名前のスクリプトが優先してインポートされます。これは、標準ライブラリを意図して置き換えているのでない限りは間違いのもとです。より詳しい情報は 標準モジュール を参照してください。
6.1.3. "コンパイル" された Python ファイル¶
モジュールの読み込みを高速化するため、Python はコンパイル済みの各モジュールを __pycache__
ディレクトリの module.version.pyc
ファイルとしてキャッシュします。ここで version はコンパイルされたファイルのフォーマットを表すもので、一般的には Python のバージョン番号です。例えば、CPython のリリース 3.3 の、コンパイル済みの spam.py は __pycache__/spam.cpython-33.pyc
としてキャッシュされるでしょう。この命名の慣習により、Python の異なる複数のリリースやバージョンのコンパイル済みモジュールが共存できます。
Python はソースの変更日時をコンパイル済みのものと比較し、コンパイル済みのものが最新でなくなり再コンパイルが必要になっていないかを確認します。これは完全に自動で処理されます。また、コンパイル済みモジュールはプラットフォーム非依存なため、アーキテクチャの異なるシステム間で同一のライブラリを共有することもできます。
Python は2つの場合にキャッシュのチェックを行いません。ひとつは、コマンドラインから直接モジュールが読み込まれた場合で、常に再コンパイルされ、結果を保存することはありません。2つめは、ソース・モジュールのない場合で、キャッシュの確認を行いません。ソースのない (コンパイル済みのもののみの) 配布をサポートするには、コンパイル済みモジュールはソース・ディレクトリになくてはならず、ソース・ディレクトリにソース・モジュールがあってはいけません。
エキスパート向けのTips:
コンパイル済みモジュールのサイズを小さくするために、Python コマンドに
-O
または-OO
スイッチを使うことができます。-O
スイッチは assert ステートメントを除去し、-OO
スイッチは assert ステートメントと __doc__ 文字列を除去します。いくつかのプログラムはこれらの除去されるものに依存している可能性があるため、自分が何をしているかを理解しているときに限ってこれらのオプションを使うべきです。"最適化" されたモジュールはopt-
タグを持ち、通常のコンパイル済みモジュールよりサイズが小さくなります。将来のリリースでは最適化の影響が変わる可能性があります。.pyc
ファイルや.pyo
ファイルから読み出されたとしても、プログラムは.py
ファイルから読み出されたときより何ら高速に動作するわけではありません。.pyc
ファイルで高速化されるのは、読み込みにかかる時間だけです。compileall
モジュールを使ってディレクトリ内の全てのモジュールに対して .pyc ファイルを作ることができます。この処理に関する詳細は、判定のフローチャートを含めて、PEP 3147 に記載されています。
6.2. 標準モジュール¶
Python は標準モジュールライブラリを同梱していて、別の Python ライブラリリファレンスというドキュメントで解説しています。幾つかのモジュールは言語のコアにはアクセスしないものの、効率や、システムコールなどOSの機能を利用するために、インタープリター内部にビルトインされています。そういったモジュールセットはまたプラットフォームに依存した構成オプションです。例えば、 winreg
モジュールは Windows システムでのみ提供されています。 1つ注目に値するモジュールとして、 sys
モジュールは、全ての Python インタープリターにビルトインされています。 sys.ps1
と sys.ps2
という変数は一次プロンプトと二次プロンプトに表示する文字列を定義しています:
>>> import sys
>>> sys.ps1
'>>> '
>>> sys.ps2
'... '
>>> sys.ps1 = 'C> '
C> print('Yuck!')
Yuck!
C>
これらの二つの変数は、インタプリタが対話モードにあるときだけ定義されています。
変数 sys.path
は文字列からなるリストで、インタプリタがモジュールを検索するときのパスを決定します。 sys.path
は環境変数 PYTHONPATH
から得たデフォルトパスに、 PYTHONPATH
が設定されていなければ組み込みのデフォルト値に設定されます。標準的なリスト操作で変更することができます:
>>> import sys
>>> sys.path.append('/ufs/guido/lib/python')
6.3. dir()
関数¶
組込み関数 dir()
は、あるモジュールがどんな名前を定義しているか調べるために使われます。 dir()
はソートされた文字列のリストを返します:
>>> import fibo, sys
>>> dir(fibo)
['__name__', 'fib', 'fib2']
>>> dir(sys)
['__breakpointhook__', '__displayhook__', '__doc__', '__excepthook__',
'__interactivehook__', '__loader__', '__name__', '__package__', '__spec__',
'__stderr__', '__stdin__', '__stdout__', '__unraisablehook__',
'_clear_type_cache', '_current_frames', '_debugmallocstats', '_framework',
'_getframe', '_git', '_home', '_xoptions', 'abiflags', 'addaudithook',
'api_version', 'argv', 'audit', 'base_exec_prefix', 'base_prefix',
'breakpointhook', 'builtin_module_names', 'byteorder', 'call_tracing',
'callstats', 'copyright', 'displayhook', 'dont_write_bytecode', 'exc_info',
'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info',
'float_repr_style', 'get_asyncgen_hooks', 'get_coroutine_origin_tracking_depth',
'getallocatedblocks', 'getdefaultencoding', 'getdlopenflags',
'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile',
'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval',
'gettrace', 'hash_info', 'hexversion', 'implementation', 'int_info',
'intern', 'is_finalizing', 'last_traceback', 'last_type', 'last_value',
'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks',
'path_importer_cache', 'platform', 'prefix', 'ps1', 'ps2', 'pycache_prefix',
'set_asyncgen_hooks', 'set_coroutine_origin_tracking_depth', 'setdlopenflags',
'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr',
'stdin', 'stdout', 'thread_info', 'unraisablehook', 'version', 'version_info',
'warnoptions']
引数がなければ、 dir()
は現在定義している名前を列挙します:
>>> a = [1, 2, 3, 4, 5]
>>> import fibo
>>> fib = fibo.fib
>>> dir()
['__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys']
変数、モジュール、関数、その他の、すべての種類の名前をリストすることに注意してください。
dir()
は、組込みの関数や変数の名前はリストしません。これらの名前からなるリストが必要なら、標準モジュール builtins
で定義されています:
>>> import builtins
>>> dir(builtins)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException',
'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning',
'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError',
'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning',
'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False',
'FileExistsError', 'FileNotFoundError', 'FloatingPointError',
'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError',
'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError',
'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError',
'MemoryError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented',
'NotImplementedError', 'OSError', 'OverflowError',
'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError',
'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning',
'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError',
'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError',
'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError',
'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning',
'ValueError', 'Warning', 'ZeroDivisionError', '_', '__build_class__',
'__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs',
'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable',
'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits',
'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit',
'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr',
'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass',
'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview',
'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property',
'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice',
'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars',
'zip']
6.4. パッケージ¶
パッケージ (package) は、Python のモジュール名前空間を "ドット付きモジュール名" を使って構造化する手段です。例えば、モジュール名 A.B
は、 A
というパッケージのサブモジュール B
を表します。ちょうど、モジュールを利用すると、別々のモジュールの著者が互いのグローバル変数名について心配しなくても済むようになるのと同じように、ドット付きモジュール名を利用すると、 NumPy や Pillow のように複数モジュールからなるパッケージの著者が、互いのモジュール名について心配しなくても済むようになります。
音声ファイルや音声データを一様に扱うためのモジュールのコレクション ("パッケージ") を設計したいと仮定しましょう。 音声ファイルには多くの異なった形式がある (通常は拡張子、 例えば .wav
, .aiff
, .au
などで認識されます) ので、増え続ける様々なファイル形式を相互変換するモジュールを、 作成したりメンテナンスしたりする必要があるかもしれません。 また、 音声データに対して実行したい様々な独自の操作 (ミキシング、 エコーの追加、 イコライザ関数の適用、 人工的なステレオ効果の作成など) があるかもしれません。 そうなると、 こうした操作を実行するモジュールを果てしなく書くことになるでしょう。 以下に (階層的なファイルシステムで表現した) パッケージの構造案を示します:
sound/ Top-level package
__init__.py Initialize the sound package
formats/ Subpackage for file format conversions
__init__.py
wavread.py
wavwrite.py
aiffread.py
aiffwrite.py
auread.py
auwrite.py
...
effects/ Subpackage for sound effects
__init__.py
echo.py
surround.py
reverse.py
...
filters/ Subpackage for filters
__init__.py
equalizer.py
vocoder.py
karaoke.py
...
パッケージを import する際、 Python は sys.path
上のディレクトリを検索して、トップレベルのパッケージの入ったサブディレクトリを探します。
ファイルを含むディレクトリをパッケージとしてPython に扱わせるには、ファイル __init__.py
が必要です(より高度な機能 namespace package を使う場合を除く)。
これにより、 string
のようなよくある名前のディレクトリにより、モジュール検索パスの後の方で見つかる正しいモジュールが意図せず隠蔽されてしまうのを防ぐためです。
最も簡単なケースでは __init__.py
はただの空ファイルで構いませんが、 __init__.py
ではパッケージのための初期化コードを実行したり、後述の __all__
変数を設定してもかまいません。
パッケージのユーザは、個々のモジュールをパッケージから import することができます。例えば:
import sound.effects.echo
この操作はサブモジュール sound.effects.echo
をロードします。このモジュールは、以下のように完全な名前で参照しなければなりません。
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)
サブモジュールを import するもう一つの方法を示します:
from sound.effects import echo
これもサブモジュール echo
をロードし、パッケージ名なしで利用可能にします。なのでこう使えます:
echo.echofilter(input, output, delay=0.7, atten=4)
さらにもう一つのバリエーションとして、必要な関数や変数を直接 import する方法があります:
from sound.effects.echo import echofilter
また、これもサブモジュール echo
をロードしますが、 echofilter()
関数を直接利用可能にします:
echofilter(input, output, delay=0.7, atten=4)
from package import item
を使う場合、 item はパッケージ package のサブモジュール (またはサブパッケージ) でもかまいませんし、関数やクラス、変数のような、 package で定義されている別の名前でもかまわないことに注意してください。 import
文はまず、 item がパッケージ内で定義されているかどうか調べます。定義されていなければ、 item はモジュール名であると仮定して、モジュールをロードしようと試みます。もしモジュールが見つからなければ、 ImportError
が送出されます。
反対に、 import item.subitem.subsubitem
のような構文を使った場合、最後の subsubitem
を除く各要素はパッケージでなければなりません。最後の要素はモジュールかパッケージにできますが、一つ前の要素で定義されているクラスや関数や変数にはできません。
6.4.1. パッケージから * を import する¶
それでは、ユーザが from sound.effects import *
と書いたら、どうなるのでしょうか?理想的には、何らかの方法でファイルシステムが調べられ、そのパッケージにどんなサブモジュールがあるかを調べ上げ、全てを import する、という処理を望むことでしょう。これには長い時間がかかってしまうこともありますし、あるサブモジュールを import することで、そのモジュールが明示的に import されたときのみ発生して欲しい副作用が起きてしまうかもしれません。
唯一の解決策は、パッケージの作者にパッケージの索引を明示的に提供させる というものです。 import
文の使う規約は、パッケージの __init__.py
コードに __all__
という名前のリストが定義されていれば、 from package import *
が現れたときに import すべきモジュール名のリストとして使う、というものです。 パッケージの新バージョンがリリースされるときにリストを最新の状態に更新するのは パッケージの作者の責任となります。 自分のパッケージから * を import するという使い方が考えられないならば、 パッケージの作者はこの使い方をサポートしないことにしてもかまいません。 例えば、ファイル sound/effects/__init__.py
には、次のような コードを入れてもよいかもしれません:
__all__ = ["echo", "surround", "reverse"]
これが意味するのは、 from sound.effects import *
とすると、名前の挙がった 3つのサブモジュールが sound.effects
パッケージから import される、ということです。
注意点として、サブモジュールはローカルな名前で隠されることがあります。例として、 reverse
関数を sound/effects/__init__.py
に足すと、 from sound.effects import *
では echo
と surround
の2サブモジュールだけ import されます。 reverse
サブモジュールは import されません 。それはローカルに定義された reverse
関数で隠されたので:
__all__ = [
"echo", # refers to the 'echo.py' file
"surround", # refers to the 'surround.py' file
"reverse", # !!! refers to the 'reverse' function now !!!
]
def reverse(msg: str): # <-- this name shadows the 'reverse.py' submodule
return msg[::-1] # in the case of a 'from sound.effects import *'
もしも __all__
が定義されていなければ、実行文 from sound.effects import *
は、パッケージ sound.effects
の全てのサブモジュールを現在の名前空間の中へ import しません 。この文は単に(場合によっては初期化コード __init__.py
を実行して) パッケージ sound.effects
が import されたということを確認し、そのパッケージで定義されている名前を全て import するだけです。 import される名前には、 __init__.py
で定義された名前 (と、明示的にロードされたサブモジュール) が含まれます。パッケージのサブモジュールで、以前の import
文で明示的にロードされたものも含みます。以下のコードを考えてください:
import sound.effects.echo
import sound.effects.surround
from sound.effects import *
上の例では、 echo
と surround
モジュールが現在の名前空間に import されます。これらのモジュールは from...import
文が実行された際に sound.effects
内で定義されているからです。 (この機構は __all__
が定義されているときにも働きます。)
特定のモジュールでは import *
を使ったときに、特定のパターンに従った名前のみを公開 (export) するように設計されてはいますが、それでもやはり製品のコードでは良いことではないと考えます。
from package import specific_submodule
を使っても何も問題はないことに留意してください!実際この表記法は、import を行うモジュールが他のパッケージと同じ名前を持つサブモジュールを使わなければならない場合を除いて推奨される方式です。
6.4.2. パッケージ内参照¶
パッケージが (前述の例の sound
パッケージのように) サブパッケージの集まりに構造化されている場合、絶対 import を使って兄弟関係にあるパッケージを参照できます。例えば、モジュール sound.filters.vocoder
で sound.effects
パッケージの echo
モジュールが必要な場合、 from sound.effects import echo
が使えます。
また、明示的な相対importを from module import name
の形式の import 文で利用できます。この明示的な相対 import では、先頭のドットで現在および親パッケージを指定します。 surround
モジュールの例では、以下のように記述できます:
from . import echo
from .. import formats
from ..filters import equalizer
相対 import は現在のモジュール名をベースにすることに注意してください。メインモジュールの名前は常に "__main__"
なので、Python アプリケーションのメインモジュールとして利用されることを意図しているモジュールでは絶対 import を利用するべきです。
6.4.3. 複数ディレクトリ中のパッケージ¶
Packages support one more special attribute, __path__
. This is
initialized to be a list containing the name of the directory holding the
package's __init__.py
before the code in that file is executed. This
variable can be modified; doing so affects future searches for modules and
subpackages contained in the package.
この機能はほとんど必要にはならないのですが、パッケージ内存在するモジュール群を拡張するために使うことができます。
脚注