1

pythonは__class__変数をcellsuper()コールに置き換えます。このセルは、最初のスタックフレームの変数freeから取得されます。pythonに格納されている `__class__`変数はどこですか?また、コンパイラはどこでそれを見つけるのかを知っています

この変数はlocals()ではありませんが、奇妙なことは__init__メソッドから参照しただけです。例えば

テイクコードのこのビット:

class LogicGate: 
    def __init__(self,n): 
     print(locals()) 
     a = __class__ 
     print(locals()) 

あなたはこれを分解し、あなたが何らかの形でそれを見ることができるがprintlocalsはグローバルであり、__class__LOAD_DEREFであることを知っています。コードを実行する前に、コンパイラはこれをどのように知っていますか? localsprintおよび__class__は、私が知る限り、コンパイラの変数名です。また、このように__class__aにコピーされる前でさえ、すべてがlocals()に突然入っています。

4   10 LOAD_DEREF    0 (__class__) 

localsながら:私はjavascriptのコンパイラへのpython skulpt働いているので、私は聞いてるのよ

  2 LOAD_GLOBAL    1 (locals) 

。現在、コンパイラはprintまたは__class__を区別せず、両方をグローバルスコープから取得しようとしています。

あなたは上記のコードビットのASTのプリントアウトからわかるように、パーサはlocalsまたは__class__を区別しません:

Module(body=[ClassDef(name='LogicGate', 
    bases=[], 
    keywords=[], 
    body=[FunctionDef(name='__init__', 
     args=arguments(args=[arg(arg='self', 
           annotation=None), 
          arg(arg='n', 
            annotation=None)], 
         vararg=None, 
         kwonlyargs=[], 
         kw_defaults=[], 
         kwarg=None, 
         defaults=[]), 
     body=[Expr(value=Call(func=Name(id='print', 
             ctx=Load()), 
               # here's the load for locals 
           args=[Call(func=Name(id='locals', 
                ctx=Load()), 
             args=[], 
             keywords=[])], 
           keywords=[])), 
       Assign(targets=[Name(id='a', 
            ctx=Store())], 
          # here's the load for __class__ 
        value=Name(id='__class__', 
           ctx=Load())), 
       Expr(value=Call(func=Name(id='print', 
             ctx=Load()), 
           args=[Call(func=Name(id='locals', 
                ctx=Load()), 
             args=[], 
             keywords=[])], 
           keywords=[]))], 
     decorator_list=[], 
     returns=None)], 
    decorator_list=[])]) 
+0

問題は、python2であなたがどこからともなく '__class__'を参照することはできません場合、私は一部を発見しました。それはDEREFには及ばない。 – albertjan

+0

あなたはPython 2またはPython 3を使用していますか? '__class__'セルは、' super'がargsなしで呼び出されるようにするPython 3のハックです。 – Dunes

答えて

2

__class__セルを可能にするためにはPython 3でハックですsuperはargなしで呼び出されます。 Python 2では、定型引数を持つsuperを呼び出す必要がありました(つまり、super(<current class>, self))。

__class__セル自体は<function>.__closure__タプルに格納されています。 __class__セルのインデックスは、<function>.__code__.co_freevarsタプルでそのインデックスを見つけることによって得ることができる。機能セルを使用しない場合、例えば、

>>> class A: 
    def __init__(self): 
     super().__init__() 

>>> A.__init__.__code__.co_freevars 
('__class__',) 
>>> A.__init__.__closure__ 
(<cell at 0x03EEFDF0: type object at 0x041613E0>,) 
>>> A.__init__.__closure__[ 
     A.__init__.__code__.co_freevars.index('__class__') 
    ].cell_contents 
<class '__main__.A'> 

しかしながら、機能に応じて、co_freevars__closure__Noneであってもよいです。さらに、__class__は存在することが保証されていません。 __class__セルは、superという関数がargsなしで呼び出された場合(実際にはsuper = print; super()などのスーパーである必要はありません)、__class__セルを作成するためにコンパイラを欺くでしょう。__class__が明示的に参照され、ローカルでない場合にのみ存在します。また、(奇妙にもかかわらず)次のコードのように、__class__セルは、インデックス0に常にあると仮定することはできませんを示しています。

class A: 
    def greet(self, person): 
     print('hello', person) 

def create_B(___person__): 
    class B(A): 
     def greet(self): 
      super().greet(___person__) 
    return B 

B = create_B('bob') 
B().greet() # prints hello bob 

assert [c.cell_contents for c in B.greet.__closure__] == ['bob', B] 
+0

よろしくお願いします!これはどういったものが一緒に詰まっているかを明確にしています。そして、なぜ '__class__' varが突然現れるのですか?これは私が「スーパー」をスケートに加えるために取り組んでいるPRです。 https://github.com/skulpt/skulpt/pull/694 py3を追加したpython2の実装です。クラスのタイプを見つけることは興味深いことになっています。 – albertjan

+0

私が言ったように、py3の 'super'の実装は非常にハッキリです。クラス内で定義された関数が 'super'という関数を呼び出すことをコンパイラが検出すると、現在定義されているクラスの周りにクロージャを持つ関数が作成されます。 – Dunes

+0

'__class__'(そしてその後の' super() '呼び出し)は、新しいクラスを返すデコレータでクラスをラップするときに壊れるようです。 – Coburn

関連する問題