Python 3の組み込み関数を速攻理解しよう: オブジェクト/スコープ/モジュール/動的評価/入出力編:特集:タイニーレファレンス(3/3 ページ)
Python 3の組み込み関数のうち、オブジェクトやクラス、スコープ、コードの動的評価、ファイルや標準入出力を扱うものを取り上げる。
スコープ/モジュールに関連するもの
Pythonのスコープやモジュール、名前空間に関連する組み込み関数としては以下のものがある。
関数 | 説明 |
---|---|
dir | 引数に何も指定しなかった場合は、現在のローカルスコープにある名前(ローカルスコープで定義された変数、関数、クラスなど)を返送する。引数にオブジェクトを指定した場合はそのオブジェクトが持つ属性の一覧を返送する |
globals | グローバルな名前空間に存在する名前の一覧を返送する |
locals | ローカルな名前空間に存在する名前の一覧を返送する |
vars | 引数に指定したオブジェクトが持つ__dict__属性を返送する。引数を指定しなかった場合は組み込み関数localsと同様 |
スコープ/モジュールに関連する組み込み関数 |
組み込み関数dirはPythonの対話モードにおいて、現在の状況(ローカルスコープに存在する名前)を得たり、特定のオブジェクトがどのような属性を持っているかを調べたりするために使われる。構文は次のようになっている。
dir([object])
以下に使用例を示す。
>>> dir() # 現在のローカルスコープに存在している名前の一覧
['__annotations__', '__builtins__', '__doc__', '__loader__', …… 省略 ……]
>>> a = 100 # 変数aを宣言
>>> dir() # 今宣言したばかりの変数aが追加される
['__annotations__', '__builtins__', '__doc__', '__loader__', …… 省略 ……, 'a']
>>> dir(a) # 変数aが参照するオブジェクト(int型)が持つ属性の一覧
['__abs__', '__add__', '__and__', '__bool__', '__ceil__', …… 省略 ……]
Pythonの対話環境では、現在のスコープやオブジェクトがどんな名前や属性を持っているかを調べながら開発を進めていくのに組み込み関数dirを使用できる。
組み込み関数globalsは現在のグローバルな名前空間に存在する名前とその値を要素とする辞書を返送する。組み込み関数localsは現在のローカルな名前空間に存在する名前とその値を要素とする辞書を返送する。どちらの関数も引数を持たないので構文は割愛する。使用例を以下に示す。
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, …… 省略 ……}
>>> locals()
{'__name__': '__main__', '__doc__': None, '__package__': None, …… 省略 ……}
>>> num = 100 # 変数を宣言
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, ……, 'num': 100}
>>> locals()
{'__name__': '__main__', '__doc__': None, '__package__': None, ……, 'num': 100}
モジュールレベル(および対話環境のプロンプトレベル)では、これら2つの関数が返す値は同じものになる。上の例では変数numを宣言の前後でこれら2つの関数を呼び出しているが、その結果は等しい。分かりやすく差が出てくるのは、関数呼び出しを行い、関数にローカルな名前空間が作成されたタイミングだ。以下に例を示す。
>>> def testfunc(): # 関数testfuncを呼び出すとローカルな名前空間が作成される
... local_var = "local var" # ローカル変数の宣言
... print(f"globals: {globals()}") # グローバルな名前空間
... print(f"locals: {locals()}") # ローカルな名前空間
...
>>> testfunc()
globals: {'__name__': '__main__', ……, 'num': 100, 'testfunc': …… 省略 ……}
locals: {'local_var': 'local var'}
Pythonでは今見たローカル/グローバルな名前空間に加えて、組み込みの名前空間があり、ローカル→グローバル→組み込みの順に名前の検索が行われていく。
組み込み関数varsは、引数に渡したオブジェクトが辞書(__dict__属性)を持っていれば、それを返送する(__dict__属性を持つオブジェクトとしてはモジュール、クラス、クラスのインスタンス、関数などがある)。引数を指定しなかった場合は、組み込み関数localsと同様な結果を返送する。構文は次の通り。
vars([object])
使用例を以下に示す。まずは無引数で呼び出した場合だ。
>>> vars()
{'__name__': '__main__', '__doc__': None, '__package__': None, …… 省略 ……}
>>> vars() == locals() # 引数なしだと組み込み関数vars/localsは同様に振る舞う
True
「vars() == locals()」の結果がTrueとなっていることから、無引数で呼び出した場合の組み込み関数varsの結果が組み込み関数localsのものと同等であることが分かる。では、引数を指定した場合はどうだろう。
class VarsTest:
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
print(f"name: {self.name}, age: {self.age}")
def show_vars(self):
print(vars(self))
vars(VarsTest) # VarsTestクラスが持つ辞書
vt = VarsTest("someone", 18)
vt.show_vars() # VarsTestクラスのインスタンスが持つ辞書
上のコードを実行した結果を以下に示す。
>>> class VarsTest:
... def __init__(self, name, age):
... self.name = name
... self.age = age
... def show(self):
... print(f"name: {self.name}, age: {self.age}")
... def show_vars(self):
... print(vars(self))
...
>>> vars(VarsTest)
mappingproxy({'__module__': '__main__', '__init__': <function VarsTest.__init__ at
0x000001BACECB1378>, 'show': <function VarsTest.show at 0x000001BACECB16A8>,
'show_vars': <function VarsTest.show_vars at 0x000001BACECB1730>, '__dict__':
<attribute '__dict__' of 'VarsTest' objects>, '__weakref__': <attribute
'__weakref__' of 'VarsTest' objects>, '__doc__': None})
>>> vt = VarsTest("someone", 18)
>>> vt.show_vars()
{'name': 'someone', 'age': 18}
「vars(VarsTest)」呼び出しでは、VarsTestクラスが持つメソッド(show、show_varsなど)が見えていることが分かる。一方、組み込み関数varsにVarsTestクラスのインスタンスを渡した場合はそのインスタンス変数(self.〜でアクセス可能なメンバ)が列挙されていることが分かる。
Pythonコードの動的評価に関連するもの
Pythonでは文字列などに格納したPythonコードを動的に評価/実行できる。そのための組み込み関数として以下のものが提供されている。
関数 | 説明 |
---|---|
compile | 引数に指定したPythonコードをコンパイルする |
eval | 引数に指定したPythonコード(式)を評価する(代入文など、Pythonの文は渡せない) |
exec | 引数に指定したPythonコードを実行する(複数の文を実行可能。戻り値は常にNone) |
Pythonコードの動的評価に関連する組み込み関数 |
組み込み関数compileの構文を以下に示す。
compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)
組み込み関数compileはパラメーターsourceに渡されたPythonコード(文字列など)を、パラメーターmodeに指定されたモードに従ってコードオブジェクトにコンパイルする。パラメーターfilenameにはコードの読み出し元のファイルの名前もしくは何らかの識別可能な文字列を与える(一時的に文字列に格納されたコードをコンパイルする際には「"<string>"」を与えるのが一般的)。flags/dont_inherit/optimizeの3つのパラメーターについてはPython 3のドキュメント「compile」を参照されたい。コンパイル後のオブジェクトは組み込み関数eval/execで実行できる。
組み込み関数evalは、文字列に格納された単一の「Python式」を「評価」して、その結果を返す。一方、組み込み関数execは任意の「Python文」(式も含む)を「実行」する。組み込み関数execの戻り値は常にNoneなので、実際には実行するPython文の中で何らかの副作用という形でその実行結果を得ることになる。
これらの構文は次のようになっている。
eval(expression, globals=None, locals=None)
exec(object[, globals[, locals]])
両者にオプションで渡せるパラメーターglobals/localsは、評価/実行時のコンテキスト(グローバル/ローカルな名前空間)を指定するものだ。これらを指定しなかった場合は呼び出し時のコンテキストが使用される。
なお、式とは「Pythonの対話環境でプロンプトに入力すると、値が表示されるもの」と簡易的には考えられる。関数やクラスの定義、if文、for文などは「Python文」であり、これらは組み込み関数evalでは扱えない。ただし、Pythonの式は文でもあり、組み込み関数execでも実行できる。
これらの使用例を以下に示す。
num = eval("1 + 1") # 組み込み関数evalは式を評価する
s = "def func(x): return x + 1" # 関数funcを定義する文字列
exec(s) # 組み込み関数execで上記文字列を実行(関数funcが定義される)
print(func(10)) # 定義した関数funcを呼び出す: 出力結果: 11
eval("print(func(num))") # その関数を組み込み関数evalを使って呼び出し。出力結果: 3
s = """
def hello(x):
return f"hello, {x}"
print(hello("world"))
"""
exec(s) # 複数行にわたる、複数のPython文の実行。出力結果: hello, world
# ラムダ式を「eval」モードでコンパイル
code1 = compile("lambda x: x * x", "<string>", "eval")
f = eval(code1) # コードオブジェクトを組み込み関数evalで評価
print(f(3)) # 結果、得られた関数(ラムダ式)を実行。出力結果: 9
# 文字列sに格納されたPythonコードを「exec」モードでコンパイル
s = """
class ExecTest:
def __init__(self, name="insider.net"):
self.name = name
def hello(self):
print(f"hello, {self.name}")
"""
code2 = compile(s, "<string>", "exec")
exec(code2)
et = ExecTest()
et.hello() # 出力結果: hello, insider.net
ただし、これらの機能は非常に強力で、何でもできてしまうので、使用する際には細心の注意が必要だ。
コンソール/ファイルに関連するもの
コンソール(標準入出力)とファイルに関連する組み込み関数としては以下のものがある。
関数 | 説明 |
---|---|
input | コンソールからテキストを1行読み込む |
open | 指定したファイルをオープンする |
指定したテキストをコンソールに出力する | |
コンソール/ファイルに関連する組み込み関数 |
組み込み関数inputはプロンプト文字列(があれば、それ)を表示し、コンソールからテキストを1行読み込む。組み込み関数printはコンソールにテキストを出力する。それぞれの構文を以下に示す。
input([prompt])
print(*objects, sep=" ", end="\n", file=sys.stdout, flush=False)
組み込み関数printでは、カンマ区切りでオブジェクトを列挙して指定可能となっている(*objects)。パラメーターsepはそれらを区切って出力する際の区切り文字を(デフォルトは半角スペース)、パラメーターendは行末に付加する文字を(デフォルトは改行文字)、パラメーターfileは出力先を(デフォルトは標準出力)、パラメーターflushはバッファリングの有無(デフォルトはバッファリングする)を指定する。
以下に使用例を示す。
import sys
s = "str"
num = 100
# sep/end/file/flushの指定なし
print(s, num) # 出力結果: str 100
# 区切り文字を", "に指定
print(s, num, sep=", ") # 出力結果: str, 100
# 区切り文字を", "に、行末に" EOL\n"を指定
print(s, num, sep=": ", end=" EOL\n") # 出力結果: str: 100 EOL
# 標準エラー出力に出力
print(s, num, file=sys.stderr)
# コンソールからテキストを入力
name = input("your name? ")
print(f"hello, {name}")
組み込み関数openは指定したファイルをオープンし、そのファイルを表すファイルオブジェクトを返送する。構文は次の通り。
open(file, mode="r", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
パラメーターmodeにはr(読み取り用)/w(書き込み用)/x(排他的。既にファイルが存在していれば失敗)/a(追記)/b(バイナリモード)/t(テキストモード)などを指定する。パラメーターbufferingはバッファリングの方法を、encodingはエンコード/デコードに使用するエンコードを、パラメーターerrorsはエンコード/デコード時のエラーの処理方法を、パラメーターnewlineはテキストモードで読み書きを行う際の行末コードの処理方法を、closefdはファイルクローズ後にもファイルがオープンされたままとするかどうかを(標準出力など、ファイル記述子を渡した場合にクローズされないようにするために使用)、パラメーターopenerはファイルオープンで使用するカスタムのオープナーを指定する。これらの詳細についてはPython 3のドキュメント「open」を参照されたい。
以下に使用例を示す。
myfile = open("sample.txt", mode="w")
print(s, num, file=myfile)
myfile.close()
myfile = open("sample.txt")
print(myfile.readline())
myfile.close()
実際にはファイルオブジェクトが持つ各種のメソッドを使用してファイルの読み書きを行うことになると思うが、上のコードでは組み込み関数printのパラメーターfileに、オープンしたファイルを指定して書き込みを行っている。読み込みについては、ファイルオブジェクトが持つreadlineメソッドを使用している。
その他
その他の組み込み関数としてはhelpと__import__の2つがある。後者は通常は気にする必要がないので、ここでは説明を省略する。
関数 | 説明 |
---|---|
help | 引数に指定したオブジェクトについてのヘルプドキュメントを表示する。指定しなかった場合には、Pythonに組み込みの対話的ヘルプが起動する |
その他の組み込み関数 |
組み込み関数helpは、Pythonに組み込みのヘルプシステムを起動させる。引数を指定した場合は、そこからその引数に関連するヘルプドキュメントが表示される。引数を指定しなければ、対話的なヘルプシステムが起動する(終了には[Ctrl]+[C]キーを入力)。例は割愛する。
以上で、Python 3の組み込み関数の構文とその使用例についての紹介が終わった。本フォーラムでは、これからも標準ライブラリやさまざまなフレームワークやライブラリを取り上げていくつもりなので、楽しみにしていてほしい。
Copyright© Digital Advantage Corp. All Rights Reserved.