我在这里说实话:当谈到函数式编程时,我从来没有比阅读它或解决简单的问题更进一步。尽管我喜欢简洁、易于维护的源代码的想法,但我从未找到使用该范例的理由。直到今天:我想在 Python 中实现几个网络工具(如traceroute
or ping
),尽可能地“功能化”(借助scapy
,functools
和itertools
. 首先,ping
:
def tcp_ping(destination_ip, destination_port, n_probes=10, timeout=1):
source_ports = [randint(49152, 65535) for i in range(n_probes)]
probes = IP(dst=destination_ip)/TCP(sport=source_ports, dport=destination_port, flags='S')
responses = map(partial(sr, timeout=timeout, verbose=0), probes)
answered = filter(lambda x: len(x[0]) > 0, responses)
lost = filter(lambda x: x not in answered, responses)
rtts = map(lambda x: int(1000 * (x[0][0][1].time - x[0][0][0].sent_time)), answered) or [0]
return dict(loss=float(len(lost))/n_probes,
min_rtt=min(rtts),
max_rtt=max(rtts),
avg_rtt=mean(rtts),
std_rtt=std(rtts))
然后,traceroute
:
def takeuntil(predicate, iterable):
for x in iterable:
yield x
if predicate(x):
break
def traceroute_probes(destination_ip, destination_port):
ttl = 1
while ttl <= 255:
p = IP(dst=destination_ip, ttl=ttl)/TCP(dport=destination_port, flags='S')
yield p
ttl = ttl + 1
def is_finalhop(x):
return (len(x[0]) > 0 and
not x[0][0][1].haslayer('ICMP'))
def hop_ip_latency(x):
if len(x[0]) > 0:
return (x[0][0][0].ttl,
x[0][0][1].src,
max(0, int(1000 * (x[0][0][1].time - x[0][0][0].sent_time))))
else:
return (x[1][0][0].ttl, '*', 0)
def tcp_traceroute(destination_ip, destination_port, timeout=1):
responses = takeuntil(is_finalhop,
imap(partial(sr, timeout=timeout, verbose=0),
traceroute_probes(destination_ip,
destination_port)))
return map(hop_ip_latency, responses)
现在,问题:
- 我们怎样才能让这段代码更“实用”?
- 如何
traceroute
在不引入不必要的副作用的情况下增加更多复杂性(例如,在连续三个超时后停止)? - 如何在不陷入命令式/面向对象的陷阱的情况下更改
sr
(与世界的接口)行为(例如,根据 RTT 改变超时)?ping
- 是否有一种纯(r)功能语言足以实现网络工具,同时也迫使我“更具功能性”?
- 谁忘了添加
takeuntil
到 Python 的itertools
?