2014-10-03 16 views
13

yapmam ki: Neden sınıf tanımı her zaman aynı bayt kodunu üretir?

#!/usr/bin/env python 
# encoding: utf-8 

class A(object): 
    pass 

Şimdi bunu sökmeye

:

Şimdi
python -m dis test0.py 
    4   0 LOAD_CONST    0 ('A') 
       3 LOAD_NAME    0 (object) 
       6 BUILD_TUPLE    1 
       9 LOAD_CONST    1 (<code object A at 0x1004ebb30, file "test0.py", line 4>) 
      12 MAKE_FUNCTION   0 
      15 CALL_FUNCTION   0 
      18 BUILD_CLASS   
      19 STORE_NAME    1 (A) 
      22 LOAD_CONST    2 (None) 
      25 RETURN_VALUE   

Sınıf tanımında bazı ifadeler ekleyin:

#!/usr/bin/env python 
# encoding: utf-8 

class A(object): 
    print 'hello' 
    1+1 
    pass 

Ve tekrar sökmeye:

4   0 LOAD_CONST    0 ('A') 
       3 LOAD_NAME    0 (object) 
       6 BUILD_TUPLE    1 
       9 LOAD_CONST    1 (<code object A at 0x1004ebb30, file "test0.py", line 4>) 
      12 MAKE_FUNCTION   0 
      15 CALL_FUNCTION   0 
      18 BUILD_CLASS   
      19 STORE_NAME    1 (A) 
      22 LOAD_CONST    2 (None) 
      25 RETURN_VALUE   

Yeni ifadeler yeni bayt kodu içinde görünmüyor?

cevap

17

Yeni ifadeler iç içe geçmiş bayt kodunda saklanır. Sen başka bir kod nesne yüklenmiş olduğundan sizin sökme görebilirsiniz:

 9 LOAD_CONST    1 (<code object A at 0x1004ebb30, file "test0.py", line 4>) 

yerine o kod nesneyi incelemek gerekir. Bunun nedeni sınıf gövdesinin bir işlev nesnesi gibi yürütüldüğü ve daha sonra üretilecek yerel ad alanının sınıf üyelerini oluşturmak için kullanıldığıdır.

Demo:

>>> import dis 
>>> def wrapper(): 
...  class A(object): 
...   pass 
... 
>>> dis.dis(wrapper) 
    2   0 LOAD_CONST    1 ('A') 
       3 LOAD_GLOBAL    0 (object) 
       6 BUILD_TUPLE    1 
       9 LOAD_CONST    2 (<code object A at 0x104b99930, file "<stdin>", line 2>) 
      12 MAKE_FUNCTION   0 
      15 CALL_FUNCTION   0 
      18 BUILD_CLASS   
      19 STORE_FAST    0 (A) 
      22 LOAD_CONST    0 (None) 
      25 RETURN_VALUE   
>>> dis.dis(wrapper.__code__.co_consts[2]) 
    2   0 LOAD_NAME    0 (__name__) 
       3 STORE_NAME    1 (__module__) 

    3   6 LOAD_LOCALS   
       7 RETURN_VALUE   

Bu sizin ilk örneği olarak aynı kurulum olduğu; sınıf gövdesine wrapper.__code__.co_consts tuple ile erişilir, LOAD_CONST bayt kodu; endeks 2 olarak verilmiştir.

Şimdi bir sınıf gövdesini ekleyebilirsiniz:

>>> def wrapper(): 
...  class A(object): 
...   print 'hello' 
...   1+1 
...   pass 
... 
>>> dis.dis(wrapper) 
    2   0 LOAD_CONST    1 ('A') 
       3 LOAD_GLOBAL    0 (object) 
       6 BUILD_TUPLE    1 
       9 LOAD_CONST    2 (<code object A at 0x104b4adb0, file "<stdin>", line 2>) 
      12 MAKE_FUNCTION   0 
      15 CALL_FUNCTION   0 
      18 BUILD_CLASS   
      19 STORE_FAST    0 (A) 
      22 LOAD_CONST    0 (None) 
      25 RETURN_VALUE   
>>> dis.dis(wrapper.__code__.co_consts[2]) 
    2   0 LOAD_NAME    0 (__name__) 
       3 STORE_NAME    1 (__module__) 

    3   6 LOAD_CONST    0 ('hello') 
       9 PRINT_ITEM   
      10 PRINT_NEWLINE  

    4   11 LOAD_CONST    2 (2) 
      14 POP_TOP    

    5   15 LOAD_LOCALS   
      16 RETURN_VALUE   

Şimdi sınıf gövdesi görünür; Sınıf gövdesi yüklendiğinde çalıştırılacak bayt kodunu görebiliriz.

Not, her sınıf gövdesi için yürütülen LOAD_NAME ve STORE_NAME bayt kodlarıdır; Bunlar modül adını alır ve bunları yeni bir yerel ad olarak __module__ olarak depolar, böylece sınıfınız oluşturulduktan sonra bir __module__ özniteliği ile sona erer.

LOAD_LOCALS bayt kodu daha sonra bu 'işlevi' üretilen tüm yerel isimleri toplar arayana, BUILD_CLASS bayt kodu 'A' dize ve (BUILD_TUPLE ile oluşturulan) object bazlar başlığın ile birlikte kullanan, böylece bu olabilir döndürür yeni sınıf nesnesini üretin.

+0

Sweet. Bunu bilmiyordum. İlginç soru ve hoş bir cevap. (1) – NPE

İlgili konular