2012-10-31 8 views
5

Podczas dyskusji w pythonie, widziałem funkcję konwersji ciągu IP w liczbę całkowitą w sposób funkcjonalny progamming. Oto the Link.Jak zrozumieć funkcjonalny kod programowania do konwersji ciągu IP na liczbę całkowitą?

Funkcja jest realizowana w jednym wierszu.

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

Jednak mam kilka pomysłów na programowanie funkcyjne. Czy ktokolwiek mógłby wyjaśnić szczegółowo tę funkcję? Mam trochę wiedzy na temat "mapy" i "zmniejszenia". Ale nie wiem, co "|" i "chunk" znaczy tutaj.

Dzięki.

+0

Na marginesie, python zawiera tego rodzaju baterie: 'struct.unpack ('! I', socket.inet_aton (ip)) [ 0] ' – georg

+0

Zastanawiam się, jaka jest różnica w wydajności? – Keith

Odpowiedz

13

sum i chunk argumenty do funkcji lambda przekazany do reduce. | jest operatorem binarnym lub operatorem.

Rzecz działa tak:

  • ip.split(".") zwraca listę łańcuchów, z których każda odpowiada kawałek przerywana ciąg ("192.168.0.1" =>["192", "168", "0", "1"];

  • map stosuje swój pierwszy operand każdy element drugiego argumentu (["192", "168", "0", "1"] =>[192, 168, 0, 1]);

  • reduce przyjmuje dwa pierwsze argumenty z listy i stosuje do nich lambda; następnie robi to ponownie z wynikiem lambda i następnego elementu listy; i tak dalej.

  • Funkcja (funkcja anonimowa zdefiniowana na miejscu) robi to: przyjmuje pierwszy argument, przesuwa go o osiem bitów, a OR to nowa porcja; Tak więc, co się dzieje, jest to, że wynik jest obliczany następująco:

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

    który jest dokładnie to, co „przerywana forma” oznacza (to tylko skrótem do wskazania 32 bitową liczbę całkowitą bez znaku, czyli co to jest IP w protokole IPv4 - można powiedzieć, że to trochę tak, jak wyrażanie go w bazie 256)

+0

Wielkie dzięki. Zrozumiałem kod. Zastanawiam się tylko, w jaki sposób dodać funkcję do konwersji ciągu Integer na IP w ten sposób? – zfz

5

| jest bitwise, logical or:

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

Zmniejszenie Wywołuje lambda z obecnym SUMARYCZNY i następnej wartości (całkowitej) na wyjściu funkcji map(). Tak, to jest w następujący sposób w pętli:

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

gdzie map(int, ip.split(".")) okazało adres IP na ciąg liczb całkowitych; 1.2.3.4 staje się [1, 2, 3, 4].

<< jest bitwise left shift przez 8 bitów w tym przypadku:

>>> 1 << 8 
256 

Tak, dla każdej części całkowitej adresu IP, to Zmienia wartość w lewo o 8 pozycjach, i dodaje bity następnej części adresu do tego numeru.

Ma to sens, ponieważ adres IP to nic innego jak liczba 32-bitowa, a notacja ciągu dzieli tę liczbę na 4 części o 8 bitach i "drukuje" całkowitą wartość każdego z tych 8 bitów ze znakiem . pomiędzy.

Pomaga wydrukować każdą scenę w postaci liczby binarnej:

>>> 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' 
Powiązane problemy