2015-08-24 6 views
5

Manchmal sind einige Werte/Strings sind hartcodiert in Funktionen. Zum Beispiel definiere ich in der folgenden Funktion eine "Konstante", die die Zeichenfolge vergleicht und gegen sie prüft.Fest codierten Variablen in Python Funktion

def foo(s): 
    c_string = "hello" 
    if s == c_string: 
     return True 
    return False 

Ohne zu viel zu diskutieren, warum es schlecht ist, dies zu tun, und wie es in dem äußeren Umfang definiert werden soll, ich frage mich, was hinter den Kulissen passiert, wenn es ist diese Weise definiert.
Wird die Zeichenfolge bei jedem Aufruf erstellt?
Wenn anstelle der Zeichenfolge "hello" war es die Liste: [1,2,3] (oder eine Liste mit veränderbaren Inhalten, wenn es darauf ankommt) würde das gleiche passieren?

Antwort

11

Da die Zeichenfolge unveränderlich ist (genau wie ein Tupel), wird sie zusammen mit dem Bytecode-Objekt für die Funktion gespeichert. Es wird durch eine sehr einfache und schnelle Indexsuche geladen. Dies ist eigentlich schneller als eine globale Suche.

Sie können sehen, in einer Zerlegung des Bytecode, mit dem dis.dis() function:

>>> import dis 
>>> def foo(s): 
...  c_string = "hello" 
...  if s == c_string: 
...   return True 
...  return False 
... 
>>> dis.dis(foo) 
    2   0 LOAD_CONST    1 ('hello') 
       3 STORE_FAST    1 (c_string) 

    3   6 LOAD_FAST    0 (s) 
       9 LOAD_FAST    1 (c_string) 
      12 COMPARE_OP    2 (==) 
      15 POP_JUMP_IF_FALSE  22 

    4   18 LOAD_GLOBAL    0 (True) 
      21 RETURN_VALUE   

    5  >> 22 LOAD_GLOBAL    1 (False) 
      25 RETURN_VALUE   
>>> foo.__code__.co_consts 
(None, 'hello') 

Der LOAD_CONST Opcode das String-Objekt aus dem co_costs Array lädt, den Teil des Codeobjekts für die Funktion ist; Die Referenz wird an den Anfang des Stapels geschoben. Der Opcode STORE_FAST nimmt den Verweis von der Oberseite des Stapels und speichert ihn in dem lokalen Array, wiederum eine sehr einfache und schnelle Operation.

Für wandelbar Literale ({..}, [..]) spezielle OP-Codes bauen das Objekt, mit dem Inhalt noch als Konstanten behandelt, so viel wie möglich (komplexere Strukturen nur den gleichen Bausteine ​​folgen):

>>> def bar(): return ['spam', 'eggs'] 
... 
>>> dis.dis(bar) 
    1   0 LOAD_CONST    1 ('spam') 
       3 LOAD_CONST    2 ('eggs') 
       6 BUILD_LIST    2 
       9 RETURN_VALUE   

Die BUILD_LIST call erstellt das neue Listenobjekt mit zwei konstanten String-Objekten.

Interessanter Fakt: Wenn Sie ein Listenobjekt für einen Mitgliedschaftstest verwendet haben (something in ['option1', 'option2', 'option3']) Python weiß, dass das Listenobjekt niemals mutiert wird und es zur Compilierzeit in ein Tupel konvertiert (eine sogenannte Peephole-Optimierung) Gleiches gilt für eine Reihe wörtlichen, die zu einem frozenset() Objekt umgewandelt wird, aber nur in Python 3.2 und neueren Tuple or list when using 'in' in an 'if' clause?

Hinweis sehen, dass Ihre Beispielfunktion booleans eher verbosely verwendet, man konnte nur verwendet.

def foo(s): 
    c_string = "hello" 
    return s == c_string 

für genau das gleiche Ergebnis, diezu vermeidenAnrufe in Python 2 (Python 3 gemacht True und False Schlüsselwörter, so dass die Werte auch als Konstanten gespeichert werden können).

+0

Ist nicht das Gleiche geschieht mit 's ==„Hallo“'? – jonrsharpe

+0

Sie haben Recht mit dem Kommentar zu Tupel, ich hätte stattdessen nach einer Liste fragen sollen. Ich werde die Frage korrigieren. Der Rest der Antwort ist für jetzt hervorragend :) –

+0

@ArthurVaiselbuh: Ich habe jetzt auch Listen abgedeckt, sowie '{...}' Wörterbücher und Sets. –

Verwandte Themen