Wie kann ich ein Code-Objekt in Python erstellen?

Ich möchte ein neues Codeobjekt mit den Funktion types.CodeType () erstellen.
Es gibt fast keine dokumentation darüber und das bestehende sagt "nicht für schwach des herzens"
Sag mir, was ich brauche und gib mir einige Informationen über jedes Argument an types.CodeType,
Evtl. ein Beispiel veröffentlichen.

Hinweis :
Bei normalen Gebrauchsfällen brauchst du nur die eingebaute Funktion kompilieren ()
Sie sollten type.CodeType () nur verwenden, wenn Sie neue Anweisungen erstellen möchten, die nicht mit dem Schreiben von normalem Quellcode und dem direkten Zugriff auf Bytecode erhalten werden konnten.

  • Python nicht interpretiert geänderte Dateien, mit veralteten .pyc
  • Marschall Laden und Ausbau
  • Warum erzeugt eine Klassendefinition immer denselben Bytecode?
  • Was ist der Vorrang von python kompilierten Dateien im Importe?
  • Der Python-Bytecode wird mit dem ursprünglichen Code verknüpft?
  • Warum sind Integer-Divisionen beim Kompilieren auf Bytecode nicht optimiert?
  • Python-Listen-Set-Wert bei Index, wenn kein Index existiert
  • Zweidimensionales Array in Python
  • Matrix Transponieren in Python
  • Wie initialisiert man ein zweidimensionales Array in Python?
  • Grundlegende Python-Programmierhilfe benötigt mit Arrays und zufälligen Standorten
  • Holen Sie sich die Indizes der N höchsten Werte in einem ndarray
  • 2 Solutions collect form web for “Wie kann ich ein Code-Objekt in Python erstellen?”

    ———–
    Haftungsausschluss :
    Die Dokumentation in dieser Antwort ist nicht offiziell und kann falsch sein.

    Diese Antwort gilt nur für python Version 3.x

    ———–

    Um ein Codeobjekt zu erstellen, müssen Sie an die Funktion CodeType () die folgenden Argumente übergeben:

    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 ) 

    Jetzt werde ich versuchen zu erklären, was die Bedeutung jedes Arguments ist.

    Argcount
    Anzahl der an die Funktion zu übermittelnden Argumente (* args und ** kwargs sind nicht enthalten).

    Kwonlyargcount
    Anzahl der Keyword-only-Argumente .

    Nlocals
    Anzahl der lokalen Variablen,
    Nämlich alle Variablen und Parameter (* args und ** kwargs enthalten) außer globalen Namen.

    Stacksize Die Menge des Stacks (virtueller Stapel), der vom Code benötigt wird,
    Wenn du verstehen möchtest, wie es funktioniert, siehe offizielle Dokumentation .

    Fahnen
    Eine Bitmap, die etwas über das Codeobjekt sagt:
    1 -> code wurde optimiert
    2 -> newlocals: Es gibt einen neuen lokalen Namespace (zB eine Funktion)
    4 -> Der Code akzeptiert eine beliebige Anzahl von Positionsargumenten (* args wird verwendet)
    8 -> der Code akzeptiert eine beliebige Anzahl von Keyword-Argumenten (* kwargs wird verwendet)
    32 -> der code ist ein generator

    Othes flags werden in älteren pythonversionen verwendet oder werden aktiviert, um zu sagen, was aus __ future importiert wird __

    Codestring
    Eine Folge von Bytes, die Bytecode-Befehle darstellen
    Wenn Sie ein besseres Verständnis wünschen, siehe Dokumentation (wie oben)

    Consts
    Ein Tupel mit Literaten, die vom Bytecode verwendet werden (zB vorberechneten Zahlen, Tupel und Strings)

    Namen
    Ein Tupel mit Namen, die vom Bytecode verwendet werden
    Diese Namen sind globale Variablen, Funktionen und Klassen oder auch Attribute, die von Objekten geladen werden

    Varnames
    Ein Tupel mit lokalen Namen, die vom Bytecode verwendet werden (Argumente zuerst, dann lokale Variablen)

    Dateiname
    Es ist der Dateiname, aus dem der Code kompiliert wurde.
    Es kann sein, was auch immer du willst, du bist frei, darüber zu lügen. 😉

    Name
    Es gibt den Namen der Funktion. Auch das kann alles sein, was du willst, aber sei vorsichtig:
    Dies ist der Name, der im Traceback angezeigt wird, wenn der Name unklar ist, könnte der Traceback unklar sein,
    Denken Sie nur darüber nach, wie Lambdas ärgerlich sein kann.

    Firstlineno
    Die erste Zeile der Funktion (für Debug-Zweck, wenn Sie Quellcode kompiliert)

    Lnotab
    Eine Zuordnung von Bytes, die Bytecode-Offsets zu Zeilennummern korreliert.
    (Ich denke auch das ist für Debug-Zweck, es gibt nur wenige Unterlagen darüber)

    Freevars
    Ein Tupel mit den Namen der freien Variablen.
    Freie Variablen sind Variablen, die im Namespace deklariert wurden, wo das Codeobjekt definiert wurde, werden sie verwendet, wenn verschachtelte Funktionen deklariert sind;
    Dies geschieht nicht auf Modul-Ebene, denn in diesem Fall sind freie Variablen auch globale Variablen.

    Cellvars
    Ein Tupel mit Namen lokaler Variablen, auf die von verschachtelten Funktionen verwiesen wird.

    ————
    Beispiele :
    Folgende Beispiele sollen die Bedeutung des oben Gesagten klären.

    Hinweis : In fertigen Codeobjektattributen , die oben erwähnt wurden, haben Sie das co_ Präfix,
    Und eine Funktion speichert ihren ausführbaren Körper im Attribut __code__

    ————
    1. Beispiel

     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) 

    Ausgabe:

     2 5 ('a', 'b', 'k', 'w', 'p') 3 67 ('c' ,) (None, 10, 1, 'two'. 3, (1, 'two', 3)) 
    1. Es werden zwei Argumente an diese Funktion übergeben ("a", "b")

    2. Diese Funktion hat zwei Parameter ("a", "b") und drei lokale Variablen ("k", "w", "p")

    3. Demontage des Funktionsbytecodes erhalten wir dies:

       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: [] 

      Wie Sie feststellen können, dass Chile die Funktion ausführt, haben wir nie mehr als drei Elemente im Stack (Tupel zählt als seine Länge in diesem Fall)

    4. Flag Wert ist dec 67 = bin 1000011 = bin 1000000 +10 +1 = dec 64 +2 +1, also verstehen wir das

      • Der Code ist optimiert (da der größte Teil des automatisch generierten Codes ist)
      • Beim Ausführen der Funktion Bytecode lokalen Namespace Änderungen
      • 64 Eigentlich weiß ich nicht was ist seine Bedeutung
    5. Der einzige globale Name, der in der Funktion verwendet wird, ist "c", er wird in co_names gespeichert

    6. Jedes explizite Literal, das wir verwenden, wird in co_consts gespeichert:

      • Keiner ist der Rückgabewert der Funktion
      • Wir weisen ausdrücklich die Nummer 10 auf w auf
      • Wir weisen ausdrücklich (1, 'zwei', 3) auf p
      • Wenn das Tupel eine Konstante ist, ist jedes Element dieses Tupels eine Konstante, also 1, "zwei", 3 sind Konstanten

    ————
    2. Beispiel

     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) 

    Ausgabe:

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

    Die Bedeutung der Ausgabe ist das:

    Erste und zweite Zeile werden gedruckt, wenn F ausgeführt wird, also zeigen sie co_freevars und co_names von G-Code:
    "FunctionVar" befindet sich im Namespace der F-Funktion, wobei G erstellt wurde,
    "ModuleVar" ist stattdessen eine Modulvariable, also gilt sie als global.

    Nach drei Zeilen sind über co_cellvars, co_freevars und co_names Attribute von F-Code:
    "FunctionVar" wird in der G verschachtelten Funktion referenziert, also ist es als cellvar markiert,
    "ModuleVar" befindet sich im Namensraum, in dem F erstellt wurde, aber es ist eine Modulvariable,
    So ist es nicht als freevar markiert, aber es ist in globalen Namen gefunden.
    Auch der eingebaute Funktionsdruck ist in Namen und alle Namen der in F. verwendeten Attribute markiert.

    ————
    3. Beispiel

    Dies ist eine Arbeitscode-Objekt-Initialisierung,
    Das ist unbrauchbar, aber du kannst alles tun, was du mit dieser Funktion willst.

     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" 

    Ausgabe:

     5 6 

    Beispiel Die Verwendung des CodeType-Konstruktors findet sich in der Standardbibliothek, speziell Lib / modulefinder.py. Wenn du dort hinschaust, wirst du sehen, dass es verwendet wird, um das schreibgeschützte co_filename Attribut auf allen co_filename in einer Datei neu zu definieren.

    Vor kurzem lief ich in einen ähnlichen Gebrauchsfall, wo ich eine Funktionsfabrik hatte, aber die generierten Funktionen hatten immer den "generischen" Namen im Traceback, also musste ich die Codeobjekte regenerieren, um den gewünschten Namen zu enthalten.

     >>> 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!' 

    Aber warten Sie, die Funktion ist __code__ Mitglied ist nicht schreibgeschützt, so können wir tun, was der Modulfinder tut:

     >>> 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 

    Die Sache, die in diesem Beispiel zu beachten ist, ist, dass der co_name das co_name Attribut verwendet, nicht das func.__name__ Attribut beim func.__name__ von Werten in der Stack-Trace.

    Eine weitere Anmerkung: Das oben ist Python 3, um es Python 2 kompatibel zu machen, lassen Sie einfach das zweite Argument an den Konstruktor ( co_kwonlyargcount ).

    Python ist die beste Programmiersprache der Welt.