5

在 python 讨论中,我看到了一个以函数式编程方式将 IP 字符串转换为整数的函数。这是链接

该功能在一行中实现。

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

但是,我对函数式编程的想法很少。有人能详细解释一下这个功能吗?我对“map”和“reduce”有一些了解。但我不知道什么是“|” 和“块”在这里的意思。

谢谢。

4

2 回答 2

13

sum并且chunklambda传递给的函数的参数reduce|是二元或运算符。

事情是这样的:

  • ip.split(".")返回一个字符串列表,每个字符串对应一个带点的字符串 ( "192.168.0.1"=> ["192", "168", "0", "1"];

  • map将其第一个操作数应用于其第二个操作数 ( ["192", "168", "0", "1"]=> [192, 168, 0, 1]) 的每个元素;

  • reduce从列表中获取前两个参数并将其应用于lambda它们;然后它使用 lambda 的结果和列表的下一个元素再次执行此操作;等等。

  • labmda函数(现场定义的匿名函数)执行以下操作:获取第一个参数,将其移动 8 位,然后将新块与它进行 OR 运算;因此,结果是这样计算的:

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

    这正是“点形式”所代表的(它只是表示 32 位无符号整数的简写,这就是 IPv4 中的 IP - 你可以说它有点像用 base 256 表示它)

于 2012-10-31T10:58:58.023 回答
5

|按位、逻辑或

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

减少lambda使用当前运行总计和map()函数输出的下一个(整数)值调用。因此,它在循环中执行以下操作:

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

其中map(int, ip.split("."))将 IP 地址转换为整数序列;1.2.3.4变成[1, 2, 3, 4].

<<位左移,在这种情况下为 8 位:

>>> 1 << 8
256

因此,对于 IP 地址的每个整数部分,它将值向左移动 8 个位置,并将地址的下一部分的位添加到该数字。

这很有意义,因为 IP 地址只不过是一个 32 位数字,而字符串表示法将该数字分成 4 个 8 位块,并.用之间。

它有助于将每个阶段打印为二进制数:

>>> 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'
于 2012-10-31T10:55:10.600 回答