11

私はPythonのマジックメソッドについて読んでいて、それらをオーバーライドすることとそれらが何を提供するかについて多くの情報を見つけましたが、言語固有の演算子とアクションがそれらにマップされている場所を見つけることができませんでしたメソッド (+を探す__add__、 を+=探す__iadd__、クラスから新しいオブジェクトを作成すると、 __new__and__init__などが呼び出される可能性があります。Python インタープリター (または下位レベルのメカニズム) がプラス記号に遭遇したときに何が起こるかを確認できる場所はありますか?

4

5 に答える 5

5

あなたの質問は少し一般的です。「特別なメソッド」の包括的なリストがありますが、いくつかの stdlib 固有のメソッドが欠落しています (たとえば__setstate__、など__getstate__によって使用されます。ただし、これは言語プロトコルpickleではなくモジュールのプロトコルです)。pickle

インタープリターが何をするかを正確に知りたい場合は、disモジュールを使用してバイトコードを逆アセンブルできます。

>>> import dis
>>> def my_func(a):
...     return a + 2
... 
>>> dis.dis(my_func)
  2           0 LOAD_FAST                0 (a)
              3 LOAD_CONST               1 (2)
              6 BINARY_ADD          
              7 RETURN_VALUE   

BINARY_ADD加算を行う際にインターリーパーがバイトコードを実行することがわかります。実行する操作を正確に確認したい場合は、BINARY_ADDPython のソース コードをダウンロードしてceval.cファイルを確認できます。

    case BINARY_ADD:
        w = POP();
        v = TOP();
        if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) {
            /* INLINE: int + int */
            register long a, b, i;
            a = PyInt_AS_LONG(v);
            b = PyInt_AS_LONG(w);
            /* cast to avoid undefined behaviour
               on overflow */
            i = (long)((unsigned long)a + b);
            if ((i^a) < 0 && (i^b) < 0)
                goto slow_add;
            x = PyInt_FromLong(i);
        }
        else if (PyString_CheckExact(v) &&
                 PyString_CheckExact(w)) {
            x = string_concatenate(v, w, f, next_instr);
            /* string_concatenate consumed the ref to v */
            goto skip_decref_vx;
        }
        else {
          slow_add:
            x = PyNumber_Add(v, w);
        }
        Py_DECREF(v);
      skip_decref_vx:
        Py_DECREF(w);
        SET_TOP(x);
        if (x != NULL) continue;
        break;

したがって、ここでは、Python の特殊なケースで int と string の追加が行われ、最終的に にフォールバックしPyNumber_Add、最初のオペランドがそれを実装__add__して呼び出すかどうかを確認し、最終的に__radd__右側を試し、何も機能しない場合は を発生させTypeErrorます。

バイト コードはバージョン固有であるためdis、異なるバージョンでは異なる結果が表示されることに注意してください。

# python2.7
>>> def my_func():
...     return map((lambda x: x+1), range(5))
... 
>>> dis.dis(my_func)
  2           0 LOAD_GLOBAL              0 (map)
              3 LOAD_CONST               1 (<code object <lambda> at 0x16f8c30, file "<stdin>", line 2>)
              6 MAKE_FUNCTION            0
              9 LOAD_GLOBAL              1 (range)
             12 LOAD_CONST               2 (5)
             15 CALL_FUNCTION            1
             18 CALL_FUNCTION            2
             21 RETURN_VALUE        
# python3
>>> dis.dis(my_func)
  2           0 LOAD_GLOBAL              0 (map) 
              3 LOAD_CONST               1 (<code object <lambda> at 0x7f1161a76930, file "<stdin>", line 2>) 
              6 LOAD_CONST               2 ('my_func.<locals>.<lambda>') 
              9 MAKE_FUNCTION            0 
             12 LOAD_GLOBAL              1 (range) 
             15 LOAD_CONST               3 (5) 
             18 CALL_FUNCTION            1 (1 positional, 0 keyword pair) 
             21 CALL_FUNCTION            2 (2 positional, 0 keyword pair) 
             24 RETURN_VALUE  

また、将来のバージョンでは同じバイトコードが最適化される可能性があるため、バイトコードが同じであっても、異なるバージョンの python では実際には異なる命令が実行されます。

Python が舞台裏でどのように機能するかを知りたい場合は、Python の公式 Web サイトにあるチュートリアルとドキュメントに従って、C 拡張機能を作成することをお勧めします。

于 2012-11-11T18:56:33.770 に答える
4

関連する抽象化のレベルのため、演算子+を特殊なメソッドにマッピングする CPython ソースの単一の場所を特定することは自明ではありません。__add__

他の応答として、を呼び出すオペコードで+実装されます(特別に最適化された場合を除く)。一方、型オブジェクトのメンバーを調べて、メンバーが加算を実装する C 関数を指す構造体に到達します。BINARY_ADDPyNumber_AddPyNumber_Addtp_as_numberPyNumberMethodsnb_add

これは、独自の型を直接定義する 組み込み型の場合は簡単ですが、適切な. この部分は によって処理されます。 を実装するクラスを定義すると、 の機構が汎用関数に組み込まれます。この関数はオブジェクトを検索し、それを呼び出して追加を実装します。の場合、この汎用関数が呼び出され、マクロを使用して定義されます。 nb_add__add__nb_addtypeobject.c__add__typeobject.c object->type->tp_as_number->nb_add__add____add__slot_nb_addSLOT1BIN

__new__およびに関しては__init__、それらはオブジェクト自体のオペレーターから__call__typetp_call呼び出されます ( CPython 実装用語で)。Python では型を呼び出してオブジェクトを構築するため、これは論理的です。

于 2012-11-11T20:28:37.923 に答える
3

disモジュールはこれでいくらかあなたを助けることができます:

単純なリストの例を見てみましょう:

In [12]: def func():
    lis=[1,2,3]
    for i in range(5):
        lis+=[i]
   ....:         

In [13]: def func1():
    lis=[1,2,3]
    for i in range(5):
        lis =lis + [i]
   ....:         

In [14]: dis.dis(func)
  2           0 LOAD_CONST               1 (1)
              3 LOAD_CONST               2 (2)
              6 LOAD_CONST               3 (3)

             #removed some lines of code

  4          34 LOAD_FAST                0 (lis)
             37 LOAD_FAST                1 (i)
             40 BUILD_LIST               1
             43 INPLACE_ADD                       # += means inplace add is used
                                                  #     i.e `__iadd()__`
             44 STORE_FAST               0 (lis)
             47 JUMP_ABSOLUTE           28
        >>   50 POP_BLOCK           
        >>   51 LOAD_CONST               0 (None)
             54 RETURN_VALUE        

In [15]: dis.dis(func1)
  2           0 LOAD_CONST               1 (1)
              3 LOAD_CONST               2 (2)
              6 LOAD_CONST               3 (3)
              9 BUILD_LIST               3
             12 STORE_FAST               0 (lis)
             #removed some lines of code    
  4          34 LOAD_FAST                0 (lis)
             37 LOAD_FAST                1 (i)
             40 BUILD_LIST               1
             43 BINARY_ADD                          #normal binary add was used
                                                    #i.e __add__
             44 STORE_FAST               0 (lis)
             47 JUMP_ABSOLUTE           28
        >>   50 POP_BLOCK           
        >>   51 LOAD_CONST               0 (None)
             54 RETURN_VALUE        
于 2012-11-11T18:51:29.593 に答える
2

http://docs.python.org/2/library/dis.html

class x:
     def __add__(self,other):
          return "asd"

def test():
     return x() + "aaaa"



import dis
dis.dis(test)

次のようなものを返します

  2           0 LOAD_GLOBAL              0 (x)
              3 CALL_FUNCTION            0
              6 LOAD_CONST               1 ('aaaa')
              9 BINARY_ADD
             10 RETURN_VALUE

それが「低レベル」に最も近いものです

于 2012-11-11T18:50:35.673 に答える
1

ドキュメントのこの部分を確認することをお勧めします。

http://docs.python.org/3/reference/datamodel.html#special-method-names

于 2012-11-11T19:00:14.000 に答える