2012-10-31 3 views
5

In einer Python-Diskussion, sah ich eine Funktion, um IP-String in eine ganze Zahl in funktionaler Programmierung zu konvertieren. Hier ist the Link.Wie kann man den funktionalen Programmiercode zum Konvertieren von IP-Zeichenfolgen in Ganzzahlen verstehen?

Die Funktion ist in einer einzigen Zeile implementiert.

def ipnumber(ip): 
    return reduce(lambda sum, chunk: sum <<8 | chunk, map(int, ip.split("."))) 

Allerdings habe ich einige Ideen der funktionalen Programmierung. Kann jemand die Funktion im Detail erklären? Ich habe etwas Wissen von "Karte" und "reduzieren". Aber ich weiß nicht was "|" und "Brocken" bedeuten hier.

Danke.

+0

Als Randnotiz enthält python diese Art von Batterien: 'struct.unpack (, socket.inet_aton (ip 'I')) [ 0] ' – georg

+0

Ich frage mich, was der Leistungsunterschied ist? – Keith

Antwort

13

sum und chunk sind Argumente für die lambda Funktion reduce geben. | ist der binäre Operator.

Das Ding funktioniert wie folgt:

  • ip.split(".") eine Liste von Strings zurückgibt, die jeweils ein Stück der gepunkteten Zeichenfolge entspricht ("192.168.0.1" =>["192", "168", "0", "1"];

  • map gilt seinen ersten Operanden jedes Element seines zweiten Operanden (["192", "168", "0", "1"] =>[192, 168, 0, 1]);

  • reduce nimmt die ersten beiden Argumente von der Liste und wendet die lambda auf sie an; dann macht es das wieder mit dem Ergebnis des Lambda und dem nächsten Element der Liste; und so weiter.

  • die Funktion labmda (eine an Ort und Stelle definierte anonyme Funktion) tut dies: Nimmt das erste Argument, verschiebt es um acht Bits und ORs dazu den neuen Chunk; So was passiert, ist, dass das Ergebnis wie berechnet:

    (((192<<8 | 168) << 8 | 0)<<8 | 1) = 192<<24 | 168<<16 | 0<<8 | 1 
    

    das ist genau das, was die „gepunktete Form“ steht (es ist nur eine Kurzschrift ein 32-Bit Integer ohne Vorzeichen, um anzuzeigen, das ist das, was ein IP in IPv4 ist - man könnte sagen, es ist ein bisschen wie es in der Basis 256) exprimierenden

+0

Vielen Dank. Ich habe den Code verstanden. Ich frage mich nur, wie man eine Funktion implementiert, um auf diese Weise einen Integer in eine IP-Zeichenkette umzuwandeln. – zfz

5

| ist ein bitwise, logical or:

>>> 0 | 1 
1 
>>> 1 | 1 
1 

Reduzieren der Anrufe lambda mit der aktuellen laufenden Summe und dem nächsten (integer) Wert der Ausgabe der map() Funktion. Also, es tut dem folgend in einer Schleife:

sum = 0 
for chunk in map(int, ip.split(".")): 
    sum = (sum << 8) | chunk 

wo map(int, ip.split(".")) die IP-Adresse in eine Folge von ganzen Zahlen gedreht; 1.2.3.4 wird [1, 2, 3, 4].

Die << ist ein bitwise left shift, durch 8 Bits in diesem Fall:

>>> 1 << 8 
256 

für jedes ganzzahlige Teil einer IP-Adresse, so, ist es, den Wert nach links verschiebt um 8 Positionen, und fügt die Bits des nächsten Teils der Adresse auf diese Nummer.

Dies ist vollkommen sinnvoll, da eine IP-Adresse nichts anderes als eine 32-Bit-Nummer ist, und die Zeichenfolgennotation teilt diese Nummer in 4 Teile von 8 Bits auf und 'druckt' den ganzzahligen Wert jedes dieser 8 Bits mit einem . Zeichen dazwischen.

Es hilft jede Stufe als binäre Zahl zu drucken:

>>> map(int, '1.2.3.4'.split('.')) 
[1, 2, 3, 4] 
>>> bin(1) 
'0b1' 
>>> bin(2) 
'0b10' 
>>> bin(3) 
'0b11' 
>>> bin(4) 
'0b100' 
>>> bin(1 << 8) 
'0b100000000' 
>>> bin(1 << 8 | 2) 
'0b100000010' 
>>> bin((1 << 8 | 2) << 8) 
'0b10000001000000000' 
>>> bin((1 << 8 | 2) << 8 | 3) 
'0b10000001000000011' 
>>> bin(((1 << 8 | 2) << 8 | 3) << 8) 
'0b1000000100000001100000000' 
>>> bin(((1 << 8 | 2) << 8 | 3) << 8 | 4) 
'0b1000000100000001100000100'