2013-04-17 17 views
9

Chciałbym utworzyć nowy obiekt kodu z funkcją types.CodeType().
Nie ma prawie żadnej dokumentacji na ten temat, a istniejący mówi "nie dla osób o słabych nerwach".
Powiedz mi, czego potrzebuję, i przekaż mi informacje o każdym argumencie przekazanym do type.CodeType,
z możliwością umieszczenia przykładu.Jak utworzyć obiekt kodu w python?

Uwaga:
W normalnych przypadkach stosowanie będzie po prostu potrzebują wbudowaną funkcję compile()
Należy użyć types.CodeType() tylko wtedy, gdy chcesz utworzyć nowe instrukcje, które nie mogły zostać uzyskane pisząc normalny kod źródłowy i które wymagają bezpośredniego dostępu do kodu bajtowego.

+1

Dlaczego tego próbujesz? Może być łatwiej osiągnąć innymi sposobami ... – mgilson

+1

http://stackoverflow.com/questions/6612449/what-are-targuments-to-the-types-codetype-python-call –

+1

FWIW, jeśli nie jest wymienione w odnośniku do języka oznacza to, że argumenty, których oczekuje, mogą być zależne od implementacji * – mgilson

Odpowiedz

28

-----------
Zastrzeżone:
Dokumentacja w tej odpowiedzi nie jest oficjalnym i mogą być nieprawidłowe.

Ta odpowiedź jest ważna tylko dla wersji Pythona 3.x

-----------

w celu stworzenia obiektu kodu trzeba przejść do CodeType funkcyjnego () następujące argumenty:

CodeType(
     argcount,    # integer 
     kwonlyargcount,  # integer 
     nlocals,    # integer 
     stacksize,   # integer 
     flags,    # integer 
     codestring,   # bytes 
     consts,    # tuple 
     names,    # tuple 
     varnames,    # tuple 
     filename,    # string 
     name,     # string 
     firstlineno,   # integer 
     lnotab,    # bytes 
     freevars,    # tuple 
     cellvars    # tuple 
     ) 

Teraz spróbuję wyjaśnić, co jest znaczeniem każdego argumentu.

argcount
Ilość argumentów mają być przekazywane do funkcji (* args i ** kwargs nie są wliczone).

kwonlyargcount
Ilość keyword-only arguments.

nlocals
liczby zmiennych lokalnych,
mianowicie wszystkie zmienne i parametry (* args i ** kwargs zestawie) z wyjątkiem globalnych nazw.

stacksize Wysokość stosu (stack) virtual machine wymaganej przez kodeks,
jeśli chcesz zrozumieć jak to działa, zobacz oficjalną Documentation.

flagi
Bitmapa, który mówi coś o obiekcie kod:
1 -> kod został zoptymalizowany
2 -> newlocals: Jest nowy lokalnej przestrzeni nazw (na przykład funkcja)
4 - > kod przyjmuje dowolną liczbę argumentów pozycyjnych (* args służy)
8 -> kod przyjmuje dowolną liczbę keyworded argumentów (* kwargs służy)
32 -> kod jest generatorem

othes flagi są stosowane w starszych wersjach Pythona lub są aktywowane, aby powiedzieć, co jest importowane z __ przyszłości __

codestring
sekwencji bajtów reprezentujących instrukcji kodu bajtowego
jeśli chcesz lepiej zrozumieć, zobaczyć Documentation (taki sam jak powyżej)

consts
krotka zawierający literały wykorzystywane przez kodu binarnego (na przykład wstępnie obliczone liczby, krotki i strln gs)

nazwy
Krotka zawierająca nazwiska używane przez kodu bajtowego
to nazwiska są globalne zmienne, funkcje i klasy lub też atrybuty załadowany z obiektów

nazwy zmiennej
krotką zawierającą nazwy lokalne używane przez kod bajtowy (najpierw argumenty, następnie zmienne lokalne)

nazwa pliku
Jest to nazwa pliku, z którego został skompilowany kod.
To może być cokolwiek chcesz, możesz swobodnie o tym kłamać. ;)

nazwa
Podaje nazwę funkcji. Również to może być cokolwiek chcesz, ale bądź ostrożny:
To jest nazwa pokazana w tracebacku, jeśli nazwa jest niejasna, ślad może być niejasny,
pomyśl tylko, jak lambdy mogą być denerwujące.

firstlineno
Pierwsza linia funkcji (dla celów debugowania, jeśli skompilowany kod źródłowy)

lnotab
Mapowanie bajtów, które koreluje przesunięcia kodu bajtowego do linii liczb.
(myślę, że jest to również dla celów debugowania, istnieje kilka dokumentacji na ten temat)

freevars
Krotka zawierająca nazwy zmiennych wolnych.
Zmienne swobodne to zmienne zadeklarowane w przestrzeni nazw, w której zdefiniowano obiekt kodu, są używane, gdy deklarowane są funkcje zagnieżdżone;
to nie dzieje się na poziomie modułu, ponieważ w tym przypadku zmienne wolne są również zmiennymi globalnymi.

cellvars
Krotka zawierająca nazwy zmiennych lokalnych odwołuje funkcji zagnieżdżonych.

------------
Przykłady:
Poniższe przykłady powinny wyjaśnić znaczenie tego, co zostało powiedziane powyżej.

Uwaga: w kod gotowy obiektów atrybuty wymienione powyżej mają co_ prefiks,
i funkcją przechowuje swoje ciało wykonywalny w __code__ atrybutu

--------- ---
1-ci Przykład

def F(a,b): 
    global c 
    k=a*c 
    w=10 
    p=(1,"two",3) 

print(F.__code__.co_argcount) 
print(F.__code__.co_nlocals , F.__code__.co_varnames) 
print(F.__code__.co_stacksize) 
print(F.__code__.co_flags) 
print(F.__code__.co_names) 
print(F.__code__.co_consts) 

wyjściowa:

2 
5 ('a', 'b', 'k', 'w', 'p') 
3 
67 
('c' ,) 
(None, 10, 1, 'two'. 3, (1, 'two', 3)) 
  1. dwa argumenty przekazywane do funkcji ("a", "b")

  2. funkcja ma dwa parametry ("a", "b") i trzy zmienne lokalne ("k", "w", "p")

  3. demontażu kodu bajtowego funkcji uzyskujemy w ten sposób:

    3   0 LOAD_FAST    0 (a)    #stack: ["a"] 
          3 LOAD_GLOBAL    0 (c)    #stack: ["a","c"] 
          6 BINARY_MULTIPLY       #stack: [result of a*c] 
          7 STORE_FAST    2 (k)    #stack: [] 
    
    4  10 LOAD_CONST    1 (10)   #stack: [10] 
         13 STORE_FAST    3 (w)    #stack: [] 
    
    5  16 LOAD_CONST    5 ((1, 'two', 3)) #stack: [(1,"two",3)] 
         19 STORE_FAST    4 (p)    #stack: [] 
         22 LOAD_CONST    0 (None)   #stack: [None] 
         25 RETURN_VALUE        #stack: [] 
    

    jak można zauważyć Chile wykonywania funkcji nigdy nie więcej niż trzech elementów w stosie (liczy krotki jak jego długość w tym przypadku) wartość

  4. bandery jest dec 67 = bin 1000011 = bin 1000000 + 10 + 1 = grudnia 64 + 2 + 1, tak więc rozumieć, że

    • kod jest optymalizowany (w większości przypadków jest automatycznie generowany kod)
    • podczas wykonywania func zmiany w lokalnej przestrzeni nazw kodu bajtowego
    • 64?Właściwie nie wiem, jaki jest jej sens
  5. jedyna nazwa globalna, która jest używana w funkcji jest „c”, jest on przechowywany w co_names

  6. każdy wyraźny dosłowne używamy są przechowywane w co_consts:

    • Brak jest wartość powrotna funkcji
    • jawnie przypisać liczbę 10 do w
    • jawnie przypisać (1 „dwa”, 3), str
    • gdy krotka jest stała każdy element z tej krotka jest stała, tak 1 „dwa”, 3 są stałymi

------------
2-ci przykład

ModuleVar="hi" 

def F(): 
    FunctionVar=106 
    UnusedVar=ModuleVar 

    def G(): 
     return (FunctionVar,ModuleVar) 

    print(G.__code__.co_freevars) 
    print(G.__code__.co_names) 

F() 
print(F.__code__.co_cellvars) 
print(F.__code__.co_freevars) 
print(F.__code__.co_names) 

wyjściowa:

('FunctionVar',) 
('ModuleVar',) 
('FunctionVar',) 
() 
('print', '__code__', 'co_freevars', 'co_names', 'ModuleVar') 

sens wyjścia to:

pierwsza i druga linia jest drukowana, gdy F jest wykonywany, więc oni pokazują co_freevars i co_names kodu G:
„FunctionVar” znajduje się w przestrzeni nazw funkcji f, gdzie G został utworzony,
"ModuleVar" zamiast tego jest zmienną modułu, więc jest uważany za globalny.

następujące linie o co_cellvars, co_freevars i co_names atrybuty kodu F:
„FunctionVar” jest określany w funkcji zagnieżdżonej G, jest zatem oznaczona jako cellvar,
„ModuleVar” znajduje się w przestrzeni nazw przypadkach Utworzono F, ale jest to zmienna modułowa, więc nie jest oznaczana jako freevar, ale znajduje się w nazwach globalnych.
również wbudowana funkcja drukowania jest oznaczona w nazwach i wszystkie nazwy atrybutów używanych w F.

------------
3-ci przykład

Jest działająca inicjalizacja obiektu kodu,
jest to niepotrzebne, ale możesz zrobić wszystko, co chcesz z tą funkcją.

MyCode= CodeType(
     0, 
     0, 
     0, 
     3, 
     64, 
     bytes([101, 0, 0, #Load print function 
       101, 1, 0, #Load name 'a' 
       101, 2, 0, #Load name 'b' 
       23,   #Take first two stack elements and store their sum 
       131, 1, 0, #Call first element in the stack with one positional argument 
       1,   #Pop top of stack 
       101, 0, 0, #Load print function 
       101, 1, 0, #Load name 'a' 
       101, 2, 0, #Load name 'b' 
       20,   #Take first two stack elements and store their product 
       131, 1, 0, #Call first element in the stack with one positional argument 
       1,   #Pop top of stack 
       100, 0, 0, #Load constant None 
       83]),   #Return top of stack 
     (None,), 
     ('print', 'a', 'b'), 
     (), 
     'PersonalCodeObject', 
     'MyCode', 
     1, 
     bytes([14,1]), 
     (), 
     ()) 

a=2 
b=3 
exec(MyCode) # code prints the sum and the product of "a" and "b" 

wyjściowa:

5 
6 
+0

Jak to znalazłeś? Poszukiwałem dokumentacji obiektów kodowych przez około rok, znając tylko krótkie uwagi na ich temat. – tox123

+0

Flaga 64 wydaje się być "NIEZIEMIANA" (zgodnie z wynikiem polecenia 'dis.code_info'). –

1

Przykład użycia konstruktora CodeType można znaleźć w standardowych biblioteki, zwłaszcza lib/modulefinder.py. Jeśli tam spojrzysz, zobaczysz, że jest on używany do ponownego zdefiniowania atrybutu "tylko do odczytu" co_filename we wszystkich obiektach kodu w pliku.

Niedawno natknąłem się na podobny przypadek użycia, w którym miałem fabrykę funkcji, ale generowane funkcje zawsze miały nazwę "ogólną" w systemie śledzenia, więc musiałem ponownie wygenerować obiekty kodu, aby zawierały pożądaną nazwę.

>>> def x(): raise NotImplementedError 
... 
>>> x.__name__ 
'x' 
>>> x.__name__ = 'y' 
>>> x.__name__ 
'y' 
>>> x() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 1, in x 
NotImplementedError 

>>> x.__code__.co_name 
'x' 
>>> x.__code__.__name__ = 'y' 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: readonly attribute 

>>> 'Gah!' 
'Gah!' 

Ale czekaj, funkcja jest __code__ członek nie jest tylko do odczytu, więc możemy zrobić to, co modulefinder robi:

>>> from types import CodeType 
>>> co = x.__code__ 
>>> x.__code__ = CodeType(co.co_argcount, co.co_kwonlyargcount, 
      co.co_nlocals, co.co_stacksize, co.co_flags, 
      co.co_code, co.co_consts, co.co_names, 
      co.co_varnames, co.co_filename, 
      'MyNewCodeName', 
      co.co_firstlineno, co.co_lnotab, co.co_freevars, 
      co.co_cellvars) 
>>> x.__code__.co_name 
'MyNewCodeName' 
>>> x() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 1, in MyNewCodeName 
NotImplementedError 

Rzecz zauważyć w tym przykładzie, że traceback używa Atrybut co_name, a nie atrybut func.__name__ podczas tworzenia wartości w stosie śledzenia.

Jeszcze jedna uwaga: Powyższe to Python 3, aby był kompatybilny z Python 2, po prostu zostaw drugi argument konstruktorowi (co_kwonlyargcount).

Powiązane problemy