Pythonのコードオブジェクトcode objectと_code__ ツールバーの

45743 ワード

Pythonのコードオブジェクトcode object__code__のプロパティ
文書ディレクトリ
  • Pythonのコードオブジェクト`code object`と`_code__` 属性
  • 0. 参考資料
  • 1. コンセプト
  • 2. 探索
  • 0.参考資料
  • What is a code object in Python? (本文の大部分はこの文章から参考にし、翻訳した)
  • inspect — Inspect live objects
  • PyCodeObjectとPythonプログラム実行
  • 1.概念
    コードオブジェクト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およびcfcellvarsであり、gfreevarsである.
  • 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で完了