2015-09-14 12 views
6

.pyc dosyam var. Sökücünün python'da nasıl çalıştığını öğrenmek için o dosyanın içeriğini anlamalıyım, yani .pyc dosya içeriğinden dis.dis(function) gibi bir çıktıyı nasıl oluşturabilirim. Örneğin, örn.Bir .pyc dosya içeriğini nasıl anlayabilirim

>>> def sqr(x): 
...  return x*x 
... 
>>> import dis 
>>> dis.dis(sqr) 
    2   0 LOAD_FAST    0 (x) 
       3 LOAD_FAST    0 (x) 
       6 BINARY_MULTIPLY  
       7 RETURN_VALUE   

Ben .pyc dosyasını kullanarak böyle bir çıkış almak gerekir. Bazı meta verileri ve bir marshaledcode nesnesini içeren

cevap

14

code nesneyi yüklemek ve kullanımının sökmeye: bisect modülü ile

import dis, marshal, sys 

# Header size changed in 3.3. It might change again, but as of this writing, it hasn't. 
header_size = 12 if sys.version_info >= (3, 3) else 8 

with open(pycfile, "rb") as f: 
    magic_and_timestamp = f.read(header_size) # first 8 or 12 bytes are metadata 
    code = marshal.load(f)      # rest is a marshalled code object 

dis.dis(code) 

Demo: Bu modülü tanımlayan sadece üst düzey kod nesne olduğunu

>>> import bisect 
>>> import dis, marshal 
>>> import sys 
>>> header_size = 12 if sys.version_info >= (3, 3) else 8 
>>> with open(bisect.__file__, "rb") as f: 
...  magic_and_timestamp = f.read(header_size) # first 8 or 12 bytes are metadata 
...  code = marshal.load(f)      # rest is bytecode 
... 
>>> dis.dis(code) 
    1   0 LOAD_CONST    0 ('Bisection algorithms.') 
       3 STORE_NAME    0 (__doc__) 

    3   6 LOAD_CONST    1 (0) 
       9 LOAD_CONST    8 (None) 
      12 LOAD_CONST    2 (<code object insort_right at 0x106a459b0, file "/Users/mpieters/Development/Library/buildout.python/parts/opt/lib/python2.7/bisect.py", line 3>) 
      15 MAKE_FUNCTION   2 
      18 STORE_NAME    2 (insort_right) 

22   21 LOAD_NAME    2 (insort_right) 
      24 STORE_NAME    3 (insort) 

24   27 LOAD_CONST    1 (0) 
      30 LOAD_CONST    8 (None) 
      33 LOAD_CONST    3 (<code object bisect_right at 0x106a45ab0, file "/Users/mpieters/Development/Library/buildout.python/parts/opt/lib/python2.7/bisect.py", line 24>) 
      36 MAKE_FUNCTION   2 
      39 STORE_NAME    4 (bisect_right) 

45   42 LOAD_NAME    4 (bisect_right) 
      45 STORE_NAME    5 (bisect) 

47   48 LOAD_CONST    1 (0) 
      51 LOAD_CONST    8 (None) 
      54 LOAD_CONST    4 (<code object insort_left at 0x106a45bb0, file "/Users/mpieters/Development/Library/buildout.python/parts/opt/lib/python2.7/bisect.py", line 47>) 
      57 MAKE_FUNCTION   2 
      60 STORE_NAME    6 (insort_left) 

67   63 LOAD_CONST    1 (0) 
      66 LOAD_CONST    8 (None) 
      69 LOAD_CONST    5 (<code object bisect_left at 0x106a45cb0, file "/Users/mpieters/Development/Library/buildout.python/parts/opt/lib/python2.7/bisect.py", line 67>) 
      72 MAKE_FUNCTION   2 
      75 STORE_NAME    7 (bisect_left) 

89   78 SETUP_EXCEPT   14 (to 95) 

90   81 LOAD_CONST    6 (-1) 
      84 LOAD_CONST    7 (('*',)) 
      87 IMPORT_NAME    8 (_bisect) 
      90 IMPORT_STAR   
      91 POP_BLOCK   
      92 JUMP_FORWARD   17 (to 112) 

91  >> 95 DUP_TOP    
      96 LOAD_NAME    9 (ImportError) 
      99 COMPARE_OP    10 (exception match) 
      102 POP_JUMP_IF_FALSE  111 
      105 POP_TOP    
      106 POP_TOP    
      107 POP_TOP    

92   108 JUMP_FORWARD    1 (to 112) 
     >> 111 END_FINALLY   
     >> 112 LOAD_CONST    8 (None) 
      115 RETURN_VALUE   

Not. İçerdiği işlevleri analiz etmek isterseniz, en üst düzey code.co_consts dizisinden yuvalanmış code nesnelerini yüklemeniz gerekir; örneğin, insort_right işlevin kod nesne LOAD_CONST 2 ile yüklenir, böylece dizinde kod nesnesi için bak:

>>> code.co_consts[2] 
<code object insort_right at 0x106a459b0, file "/Users/mpieters/Development/Library/buildout.python/parts/opt/lib/python2.7/bisect.py", line 3> 
>>> dis.dis(code.co_consts[2]) 
12   0 LOAD_FAST    2 (lo) 
       3 LOAD_CONST    1 (0) 
       6 COMPARE_OP    0 (<) 
       9 POP_JUMP_IF_FALSE  27 

13   12 LOAD_GLOBAL    0 (ValueError) 
      15 LOAD_CONST    2 ('lo must be non-negative') 
      18 CALL_FUNCTION   1 
      21 RAISE_VARARGS   1 
      24 JUMP_FORWARD    0 (to 27) 

14  >> 27 LOAD_FAST    3 (hi) 
      30 LOAD_CONST    5 (None) 
      33 COMPARE_OP    8 (is) 
      36 POP_JUMP_IF_FALSE  54 

15   39 LOAD_GLOBAL    2 (len) 
      42 LOAD_FAST    0 (a) 
      45 CALL_FUNCTION   1 
      48 STORE_FAST    3 (hi) 
      51 JUMP_FORWARD    0 (to 54) 

16  >> 54 SETUP_LOOP    65 (to 122) 
     >> 57 LOAD_FAST    2 (lo) 
      60 LOAD_FAST    3 (hi) 
      63 COMPARE_OP    0 (<) 
      66 POP_JUMP_IF_FALSE  121 

17   69 LOAD_FAST    2 (lo) 
      72 LOAD_FAST    3 (hi) 
      75 BINARY_ADD   
      76 LOAD_CONST    3 (2) 
      79 BINARY_FLOOR_DIVIDE 
      80 STORE_FAST    4 (mid) 

18   83 LOAD_FAST    1 (x) 
      86 LOAD_FAST    0 (a) 
      89 LOAD_FAST    4 (mid) 
      92 BINARY_SUBSCR  
      93 COMPARE_OP    0 (<) 
      96 POP_JUMP_IF_FALSE  108 
      99 LOAD_FAST    4 (mid) 
      102 STORE_FAST    3 (hi) 
      105 JUMP_ABSOLUTE   57 

19  >> 108 LOAD_FAST    4 (mid) 
      111 LOAD_CONST    4 (1) 
      114 BINARY_ADD   
      115 STORE_FAST    2 (lo) 
      118 JUMP_ABSOLUTE   57 
     >> 121 POP_BLOCK   

20  >> 122 LOAD_FAST    0 (a) 
      125 LOAD_ATTR    3 (insert) 
      128 LOAD_FAST    2 (lo) 
      131 LOAD_FAST    1 (x) 
      134 CALL_FUNCTION   2 
      137 POP_TOP    
      138 LOAD_CONST    5 (None) 
      141 RETURN_VALUE   

Ben şahsen eşleştirme Python sürümü dışındaki bir şeyle .pyc dosyayı ayrıştırmak çalışırken önleyeceğini ve marshal modülü. marshal biçimi temel olarak Python'un kendisinin gereksinimleriyle değişen bir iç serileştirme biçimidir. Liste anlaşmaları ve with ifadeleri ve async/await gibi yeni özellikler, C source code dışında yayımlanmayan biçime yeni eklemeler gerektirir.

Eğer bu rotaya giderseniz ve modülü kullanmaktan başka bir yolla read a code object'u yönetiyorsanız, kodun çeşitli özelliklerinden sökme işlemini ayrıştırmanız gerekir; Bunun nasıl yapılacağı hakkında ayrıntılar için dis module source belgesine bakın (örneğin, bir baytkod-ofset-ketleme haritası oluşturmak için co_firstlineno ve co_lnotab özniteliklerini kullanmanız gerekir).

+0

Amacım, bir .pyc dosyası alan ve 'dis' modülünü kullanmadan bir dis.dis() modülü gibi çıktı üreten python'a bir program yazmaktır. Bir kodun başlangıcını, hat numarasını nasıl anlayabilirim? vb bir .pyc dosyasından? –

+1

['pyc dosya formatı] hakkında kısa bir blog yazısı var (http://nedbatchelder.com/blog/200804/the_structure_of_pyc_files.html). Fakat bunların hepsini tamamen anladığınızdan eminim ki, Python'un kaynağına dalmak zorundasınız (bu alanda çok iyi belgelere sahip). – HelloWorld

+1

@NiyaSimonC: '.pyc' dosyasını sıfırdan ayrıştırmak istediğiniz anlamına mı geliyorsunuz? Bu, “marşal” formatının kendisinin ayrıştırılmasını, [bir kodun nesnesini nasıl kodladığını] görmeyi gerektirir (https://hg.python.org/cpython/file/2.7/Python/marshal.c#l423). Oradan, kod nesneleri için bilgileri ayıklayın ([datamodel] 'e bakın (https://docs.python.org/2/reference/datamodel.html), aşağı inip Dahili türleri -> kod nesneleri) ve baytları bytecode komutları (bkz. ['dis.disassemble()' işlevi] (https://hg.python.org/cpython/file/2.7/Lib/dis.py#l61). –

İlgili konular