大家新年快乐!
我初学 Python 一个星期左右,求优化下面这个函数,此函数的作用在于生成 IP 列表:
def parse_ip(ip):
ips = []
if '-' in ip:
segments = ip.split(".")
seg_index = 0
for segment in segments:
if '-' in segment:
prefix = ".".join(segments[:seg_index])
suffix = ".".join(segments[seg_index+1:])
start, end = map(int, segment.split("-"))
new_ips = [".".join(filter(lambda s: s, map(str,[prefix, ip_segment, suffix]))) for ip_segment in range(start, end +1)]
for new_ip in new_ips:
ips += parse_ip(new_ip)
break
seg_index += 1
else:
ips += [ip]
return ips
if __name__ == "__main__":
print "\n".join(parse_ip("192.168.1-2.1-10"))
输出的结果是:
192.168.1.1
192.168.1.2
192.168.1.3
192.168.1.4
192.168.1.5
192.168.1.6
192.168.1.7
192.168.1.8
192.168.1.9
192.168.1.10
192.168.2.1
192.168.2.2
192.168.2.3
192.168.2.4
192.168.2.5
192.168.2.6
192.168.2.7
192.168.2.8
192.168.2.9
192.168.2.10
求指点代码还可以怎么优化,谢谢!
1
vanxining 2016-01-01 13:06:35 +08:00 via Android
楼主是来炫耀的 :-)
|
2
firebroo 2016-01-01 13:11:28 +08:00
ddd
|
4
semut 2016-01-01 13:13:05 +08:00 1
你所说的优化是指什么?运算速度么,还是计算逻辑,这是我的代码:
#!/usr/bin/env python # -*- coding: utf-8 -*- def expand(segment): if '-' not in segment: return [segment] else: start, end = map(int, segment.split('-')) return map(str, range(start, end+1)) def parse_ip(ip): segments = ip.split('.') seg_list = map(expand, segments) return reduce(lambda lx, ly: [x+'.'+y for x in lx for y in ly], seg_list) if __name__ == "__main__": print "\n".join(parse_ip("192.168.1-2.1-10")) |
5
k9982874 2016-01-01 13:16:29 +08:00 via iPhone 2
手机看代码自动换行太难看,所以就是没好好读。
能给的建议就是把函数参数改成 parse_ip(ip_header, first_start, first_end, second_start, second_end) 函数内直接 for 循环拼接生成 ip ,不需要再去拆字符串。 字符串操作成本永远是最贵的。 |
6
holyzhou 2016-01-01 13:18:30 +08:00 1
感觉 一用上 filter , reduce , map , lambda ,列表推倒式这些,程序可读性立马就下去了
|
7
hellogbk OP @semut 谢谢,我指的是代码能不能再少一点。因为我以前学 JAVA 的,所以感觉我在写这个函数的时候还是 JAVA 的思维多一点,就想知道用 python 的想法应该怎么写。
|
8
wowpanda 2016-01-01 13:25:39 +08:00
正则
|
9
am241 2016-01-01 13:25:59 +08:00
只求代码更少可以用正则吧
|
10
syv2 2016-01-01 13:32:43 +08:00 2
回复不能写格式化的代码,我就不写函数了,反正就这么个意思:
import itertools ip = "192.168.1-2.1-10" segs = [seg for seg in ip.split('.')] segs = [[int(iter) for iter in seg.split('-')] for seg in segs] ips = itertools.product(*segs) join_fuc = lambda l: '.'.join([str(i) for i in l]) ips = [join_fuc(ip) for ip in ips] |
11
syv2 2016-01-01 13:36:22 +08:00
上面写错了。。修正一下:
import itertools ip = "192.168.1-2.1-10" segs = [seg for seg in ip.split('.')] segs = [[int(iter) for iter in seg.split('-')] for seg in segs] segs = [range(seg[0], seg[1]+1) if len(seg)==2 else range(seg[0], seg[0]+1) for seg in segs] ips = itertools.product(*segs) join_fuc = lambda l: '.'.join([str(i) for i in l]) ips = [join_fuc(ip) for ip in ips] |
12
syv2 2016-01-01 13:45:45 +08:00 1
map 改良版,关键地方还是那个 itertools.product 计算笛卡尔积
import itertools ip = "192.168.1-2.1-10" segs = [seg for seg in ip.split('.')] segs = [[int(iter) for iter in seg.split('-')] for seg in segs] segs = [range(seg[0], seg[1]+1) if len(seg)==2 else range(seg[0], seg[0]+1) for seg in segs] ips = itertools.product(*segs) ips = ['.'.join(map(str, ip)) for ip in ips] |
13
asxalex 2016-01-01 14:06:21 +08:00
```python
def parse_ip(ip): return reduce(lambda x,y: [str(i) + "." + str(j) for i in x for j in y],[[int(k)] if k.find("-") < 0 else range(*map(int, *([int(a), int(b)+1] for (a, b) in [k.split("-")]))) for k in ip.split(".")]) ``` |
16
langyu 2016-01-01 14:42:47 +08:00 2
有个库 叫 IPy 你直接用就行了
|
17
ringzero 2016-01-01 14:44:09 +08:00 1
def ip2num(ip):
ip = [int(x) for x in ip.split('.')] return ip[0] << 24 | ip[1] << 16 | ip[2] << 8 | ip[3] def num2ip(num): return '%s.%s.%s.%s' % ( (num & 0xff000000) >> 24, (num & 0x00ff0000) >> 16, (num & 0x0000ff00) >> 8, num & 0x000000ff ) def gen_ips(start, end): """生成 IP 地址""" # if num & 0xff 过滤掉 最后一段为 0 的 IP return [num2ip(num) for num in range(start, end + 1) if num & 0xff] |
18
Mark3K 2016-01-01 15:01:07 +08:00 1
from itertools import product
def parse_ip(ip_str): return ['.'.join(map(lambda x: str(x), t)) for t in product(*map(lambda x: range(int(x.split('-')[0]), int(x.split('-')[1])+1) if '-' in x else [int(x)], ip_str.split('.')))] |
19
haroldwu 2016-01-01 15:26:08 +08:00 1
如果像 clojure 一樣有 thread macro ,函數式寫法( reduce map )其實更好用 www
|
20
quietin 2016-01-01 16:04:02 +08:00 1
4 楼的答案把字符拼接改成'.'.join 就是很好的答案了
|
21
congeec 2016-01-01 17:05:21 +08:00 1
@ringzero from Python 3.2 we have int.to_bytes
>>> int.from_bytes(socket.inet_aton('192.168.1.1'), byteorder='big') 3232235777 >>> _.to_bytes(length=4, byteorder='big') b'\xc0\xa8\x01\x01' >>> socket.inet_ntoa(_) '192.168.1.1' |
22
congeec 2016-01-01 17:12:37 +08:00 1
Python 号称 battery included, 你应该用自带的 ipaddress 库,写起来方便性能还不错
|
23
poke707 2016-01-01 21:19:20 +08:00 1
基本就是参考 4 楼与 10 楼的优化计算逻辑(分段解析再求笛卡尔积)。
我来再尝试把代码意图写得更明显些 https://gist.githubusercontent.com/Ginhing/aae1096546e94921990b/raw/8f5ab916950381f2e433e752b10be8f99c72ba65/ip_segment_parser.py |
25
tt0411 2016-01-01 22:29:06 +08:00 1
|
26
Gothack 2016-01-01 22:38:40 +08:00 1
大神们都在炫技
|
27
congeec 2016-01-01 22:48:45 +08:00 via iPad 1
@syv2 还是你屌。 python 的 itertools, functools, collection 这三个库真是必须掌握呢
|
28
Orzpls 2016-01-02 13:52:34 +08:00 via Android
马克之。
|
29
menc 2016-01-03 03:03:30 +08:00
别的不说
new_ips = [".".join(filter(lambda s: s, map(str,[prefix, ip_segment, suffix]))) for ip_segment in range(start, end +1)] 这行代码你觉得这个可读性过关么 |