Pythonのコードオブジェクトcode objectと_code__ ツールバーの
45743 ワード
Pythonのコードオブジェクト
文書ディレクトリ Pythonのコードオブジェクト`code object`と`_code__` 属性 0. 参考資料 1. コンセプト 2. 探索 0.参考資料 What is a code object in Python? (本文の大部分はこの文章から参考にし、翻訳した) inspect — Inspect live objects PyCodeObjectとPythonプログラム実行 1.概念
コードオブジェクト関数 モジュール クラス ジェネレータ式 コードを実行すると、コードオブジェクトに解析されコンパイルされ、
コードオブジェクトには、命令のほかに、仮想マシンがコードを実行するために必要な追加情報も含まれています.
2.探索
以下の内容は
バージョンについては、次の点に注意してください.
まず、
以下の内容は公式文書から来ています.
ツールバーの
説明
number of arguments (not including keyword only arguments, * or ** args)
string of raw compiled bytecode
tuple of names of cell variables (referenced by containing scopes)
tuple of constants used in the bytecode
name of file in which this code object was created
number of first line in Python source code
bitmap of CO_* flags, read more here
encoded mapping of line numbers to bytecode indices
tuple of names of free variables (referenced via a function’s closure)
number of keyword only arguments (not including ** arg)
name with which this code object was defined
tuple of names of local variables
number of local variables
virtual machine stack space required
tuple of names of arguments and local variables
次のように説明します.
その他のバイトコード命令
バイトコードに含まれる命令ごとにバイト数が異なります.各命令には、仮想マシンが必要とする操作を示すオペレーティングコード
パラメータを受信しないオペレーティングコードは1バイトを占有し、受信パラメータのオペレーティングコードは3バイトを占有し、第2、第3のバイトは小端順
code object
と__code__
のプロパティ文書ディレクトリ
コードオブジェクト
code object
は、Python
内の実行可能なCPython
コードの内部表現である.実行可能なPython
コードは、次のとおりです.CPython
仮想マシンによって実行されます.コードオブジェクトには、仮想マシンの内部状態を直接操作する一連の命令が含まれています.これは、C
言語でプログラミングするときと同じです.人間が読むことができるテキストを書き、コンパイラでバイナリ形式に変換します.バイナリコード(C
のマシンコードまたはPython
のバイトコード)はCPU
(C
言語)またはCPython
の仮想マシン仮想のCPU
によって直接実行されます.コードオブジェクトには、命令のほかに、仮想マシンがコードを実行するために必要な追加情報も含まれています.
2.探索
以下の内容は
Python 3.7
で実験され,主に関数について述べる.モジュールとクラスについても、コードオブジェクトによって実現される(実際には、.pyc
ファイルにはシーケンス化されたモジュールコードオブジェクトが格納されている)が、コードオブジェクトの多くの特性は主に関数に関連している.バージョンについては、次の点に注意してください.
Python 2
において、関数のコードオブジェクトは .func_code
によってアクセスされる.Python 3
では、 .__code__
を介してアクセスする必要があります.Python 3
のコードオブジェクトは、強制キーワードパラメータco_kwonlyargcount
に対応する新しい属性keyword-only argument
を追加した.まず、
.__code__
に属する2重下線で始まる属性をコンソールで見つけます.合計15
個です.>>> li = [i for i in dir((lambda: 0).__code__) if not i.startswith('__')]
>>> print(li)
['co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_kwonlyargcount', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames']
>>> len(li)
15
以下の内容は公式文書から来ています.
ツールバーの
説明
co_argcount
number of arguments (not including keyword only arguments, * or ** args)
co_code
string of raw compiled bytecode
co_cellvars
tuple of names of cell variables (referenced by containing scopes)
co_consts
tuple of constants used in the bytecode
co_filename
name of file in which this code object was created
co_firstlineno
number of first line in Python source code
co_flags
bitmap of CO_* flags, read more here
co_lnotab
encoded mapping of line numbers to bytecode indices
co_freevars
tuple of names of free variables (referenced via a function’s closure)
co_kwonlyargcount
number of keyword only arguments (not including ** arg)
co_name
name with which this code object was defined
co_names
tuple of names of local variables
co_nlocals
number of local variables
co_stacksize
virtual machine stack space required
co_varnames
tuple of names of arguments and local variables
次のように説明します.
co_argcount
:関数受信パラメータの個数であり、*args
および**kwargs
および強制キーワードパラメータを含まない.>>> def test(a, b, c, d=1, e=2, *args, f=3, g, h=4, **kwargs):
... print(a, b, c, d, e, f, g, h, args, kwargs)
...
>>> code_obj = test.__code__
>>> code_obj.co_argcount
5
co_code
:バイナリ形式のバイトコードbytecode
は、バイト列bytes
として格納される(Python 2
にはstr
タイプで格納される).仮想マシンに一連のコマンドを提供します.関数は第1の命令から実行され、RETURN_VALUE
の命令に遭遇したときに実行を停止します.その他のバイトコード命令
bytecode instruction
は、公式ドキュメント:Python Bytecode Instructionsを参照してください.バイトコードに含まれる命令ごとにバイト数が異なります.各命令には、仮想マシンが必要とする操作を示すオペレーティングコード
opcode
があり、整数であるオプションのパラメータもあります.オペレーションコードopcode
は、1バイトの整数であるため、使用されていないものが多いにもかかわらず、最大256
個の異なるオペレーションコードがある.各オペレーティングコードには名前があり、dis
モジュールのdis
関数の出力に表示され、opcode
標準ライブラリモジュールで定義されています.>>> from opcode import opname
>>> opname
['<0>', 'POP_TOP', 'ROT_TWO', 'ROT_THREE', 'DUP_TOP', 'DUP_TOP_TWO', '<6>', '<7>', '<8>', 'NOP', 'UNARY_POSITIVE', 'UNARY_NEGATIVE', 'UNARY_NOT', '<13>', '<14>', 'UNARY_INVERT', 'BINARY_MATRIX_MULTIPLY', 'INPLACE_MATRIX_MULTIPLY', '<18>', 'BINARY_POWER', 'BINARY_MULTIPLY', '<21>', 'BINARY_MODULO', 'BINARY_ADD', 'BINARY_SUBTRACT', 'BINARY_SUBSCR', 'BINARY_FLOOR_DIVIDE', 'BINARY_TRUE_DIVIDE', 'INPLACE_FLOOR_DIVIDE', 'INPLACE_TRUE_DIVIDE', '<30>', '<31>', '<32>', '<33>', '<34>', '<35>', '<36>', '<37>', '<38>', '<39>', '<40>', '<41>', '<42>', '<43>', '<44>', '<45>', '<46>', '<47>', '<48>', '<49>', 'GET_AITER', 'GET_ANEXT', 'BEFORE_ASYNC_WITH', '<53>', '<54>', 'INPLACE_ADD', 'INPLACE_SUBTRACT', 'INPLACE_MULTIPLY', '<58>', 'INPLACE_MODULO', 'STORE_SUBSCR', 'DELETE_SUBSCR', 'BINARY_LSHIFT', 'BINARY_RSHIFT', 'BINARY_AND', 'BINARY_XOR', 'BINARY_OR', 'INPLACE_POWER', 'GET_ITER', 'GET_YIELD_FROM_ITER', 'PRINT_EXPR', 'LOAD_BUILD_CLASS', 'YIELD_FROM', 'GET_AWAITABLE', '<74>', 'INPLACE_LSHIFT', 'INPLACE_RSHIFT', 'INPLACE_AND', 'INPLACE_XOR', 'INPLACE_OR', 'BREAK_LOOP', 'WITH_CLEANUP_START', 'WITH_CLEANUP_FINISH', 'RETURN_VALUE', 'IMPORT_STAR', 'SETUP_ANNOTATIONS', 'YIELD_VALUE', 'POP_BLOCK', 'END_FINALLY', 'POP_EXCEPT', 'STORE_NAME', 'DELETE_NAME', 'UNPACK_SEQUENCE', 'FOR_ITER', 'UNPACK_EX', 'STORE_ATTR', 'DELETE_ATTR', 'STORE_GLOBAL', 'DELETE_GLOBAL', '<99>', 'LOAD_CONST', 'LOAD_NAME', 'BUILD_TUPLE', 'BUILD_LIST', 'BUILD_SET', 'BUILD_MAP', 'LOAD_ATTR', 'COMPARE_OP', 'IMPORT_NAME', 'IMPORT_FROM', 'JUMP_FORWARD', 'JUMP_IF_FALSE_OR_POP', 'JUMP_IF_TRUE_OR_POP', 'JUMP_ABSOLUTE', 'POP_JUMP_IF_FALSE', 'POP_JUMP_IF_TRUE', 'LOAD_GLOBAL', '<117>', '<118>', 'CONTINUE_LOOP', 'SETUP_LOOP', 'SETUP_EXCEPT', 'SETUP_FINALLY', '<123>', 'LOAD_FAST', 'STORE_FAST', 'DELETE_FAST', '<127>', '<128>', '<129>', 'RAISE_VARARGS', 'CALL_FUNCTION', 'MAKE_FUNCTION', 'BUILD_SLICE', '<134>', 'LOAD_CLOSURE', 'LOAD_DEREF', 'STORE_DEREF', 'DELETE_DEREF', '<139>', '<140>', 'CALL_FUNCTION_KW', 'CALL_FUNCTION_EX', 'SETUP_WITH', 'EXTENDED_ARG', 'LIST_APPEND', 'SET_ADD', 'MAP_ADD', 'LOAD_CLASSDEREF', 'BUILD_LIST_UNPACK', 'BUILD_MAP_UNPACK', 'BUILD_MAP_UNPACK_WITH_CALL', 'BUILD_TUPLE_UNPACK', 'BUILD_SET_UNPACK', 'SETUP_ASYNC_WITH', 'FORMAT_VALUE', 'BUILD_CONST_KEY_MAP', 'BUILD_STRING', 'BUILD_TUPLE_UNPACK_WITH_CALL', '<159>', 'LOAD_METHOD', 'CALL_METHOD', '<162>', '<163>', '<164>', '<165>', '<166>', '<167>', '<168>', '<169>', '<170>', '<171>', '<172>', '<173>', '<174>', '<175>', '<176>', '<177>', '<178>', '<179>', '<180>', '<181>', '<182>', '<183>', '<184>', '<185>', '<186>', '<187>', '<188>', '<189>', '<190>', '<191>', '<192>', '<193>', '<194>', '<195>', '<196>', '<197>', '<198>', '<199>', '<200>', '<201>', '<202>', '<203>', '<204>', '<205>', '<206>', '<207>', '<208>', '<209>', '<210>', '<211>', '<212>', '<213>', '<214>', '<215>', '<216>', '<217>', '<218>', '<219>', '<220>', '<221>', '<222>', '<223>', '<224>', '<225>', '<226>', '<227>', '<228>', '<229>', '<230>', '<231>', '<232>', '<233>', '<234>', '<235>', '<236>', '<237>', '<238>', '<239>', '<240>', '<241>', '<242>', '<243>', '<244>', '<245>', '<246>', '<247>', '<248>', '<249>', '<250>', '<251>', '<252>', '<253>', '<254>', '<255>']
パラメータを受信しないオペレーティングコードは1バイトを占有し、受信パラメータのオペレーティングコードは3バイトを占有し、第2、第3のバイトは小端順
little-endian order
に従ってパラメータを記憶する.パラメータが2バイトで表すことができない場合、例えば65535
より大きい場合、特殊なオペレーティングコードEXTENDED_ARG
が使用される.co_cellvars
およびco_freevars
:この2つの属性は、ネスト関数の役割ドメインを実現するために使用される.co_cellvars
メタグループには、ネストされた関数で使用されるすべての変数名が格納されています.co_freevars
メタグループには、関数によって使用されるすべての閉パケット役割ドメインで定義された変数名が格納されている.これらのメタグループ内の変数名は、アルファベット順に並べられています.次の例に示すように、a
およびc
はf
のcellvars
であり、g
のfreevars
である.def f(a, b):
c = 3
def g():
return a + c
return g
print(f.__code__.co_cellvars)
print(f.__code__.co_consts[2].co_freevars)
"""
('a', 'c')
('a', 'c')
"""
co_consts
:整数、文字列、ブール値など、関数で使用されるすべての定数.パラメータとしてインデックス値が必要なLOAD_CONST
オペランドコードで使用され、co_consts
メタグループからどの要素をロードする必要があるかを示す.co_consts
タプルの最初の要素は、関数のドキュメント文字列docstring
であり、ない場合はNone
である.co_filename
:コードオブジェクトが存在するファイル名.test.py
f = lambda: 0
print(f.__code__.co_filename)
"""
test.py
"""
co_firstlineno
:コードオブジェクトの最初の行がファイルの行番号にあります.# comment
f = lambda: 0
print(f.__code__.co_firstlineno)
"""
3
"""
co_flags
:関数の組合せブールフラグビットを格納する整数です.これらのフラグビットの具体的な意味は、inspect
モジュールのドキュメントに表示できます:Code Objects Bit Flags co_lnotab
:このプロパティはline number table
行番号テーブルの略です.これは、bytes
バイト列のオフセット量とco_code
行番号のオフセット量のペアであるバイト列Python
として格納される.詳細は、lnotab_notes.txt
co_kwonlyargcount
:必須キーワードパラメータを格納する個数.Python 2
にはこの属性はありません.>>> def test(a, b, c, d=1, e=2, *args, f=3, g, h=4, **kwargs):
... print(a, b, c, d, e, f, g, h, args, kwargs)
...
>>> code_obj = test.__code__
>>> code_obj.co_kwonlyargcount
3
co_name
:コードオブジェクトに関連付けられたオブジェクトの名前です.>>> func = lambda: 0
>>> func.__code__.co_name
''
>>> def test(): pass
...
>>> test.__code__.co_name
'test'
co_names
:この属性は文字列からなるメタグループであり、グローバル変数とインポートされた名前が使用順に格納されている.(公式ドキュメントの表ではローカル変数の名前と言われていますが、実際には間違っています)a = 1
def f(x):
x = a
print('hello')
print(f.__code__.co_names)
"""
('a', 'print')
"""
co_nlocals
:関数内の局所変数の個数であり、co_varnames
の長さに相当する.co_stacksize
:関数が使用する最大スタックスペースを表す整数.co_varnames
:関数のすべてのローカル変数名(関数パラメータを含む)からなるメタグループ.まず、位置パラメータ、デフォルトパラメータ、および強制キーワードパラメータ、次いで*args
および**kwargs
(もしあれば)が、最後に最初の使用順序で並べられた他のローカル変数である.>>> def test(a, b, c, d=1, e=2, *args, f=3, g, h=4, **kwargs):
... print(a, b, c, d, e, f, g, h, args, kwargs)
... x = 666
...
>>> code_obj = test.__code__
>>> code_obj.co_varnames
('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'args', 'kwargs', 'x')
2019.02.04
で完了