V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
zhmin
V2EX  ›  Python

怎么看待代码中,为了效率合并循环?

  •  1
     
  •   zhmin · 2015-04-24 22:12:50 +08:00 · 4562 次点击
    这是一个创建于 3283 天前的主题,其中的信息可能已经有所发展或是发生改变。
    items = [...]
    for item in items:
    do_somthing_1(item)

    for item in items:
    do_something_2(item)

    但是do_somthing_1和do_something_2是两个没有逻辑关联的过程,

    合并循环,
    for item in items:
    do_somthing_1(item)
    do_something_2(item)

    大家一般倾向于哪种习惯?
    22 条回复    2015-04-26 11:55:18 +08:00
    df4VW
        1
    df4VW  
       2015-04-24 22:14:55 +08:00
    如果确保相互不影响,你不选后者的理由是?
    ruandao
        2
    ruandao  
       2015-04-24 22:19:35 +08:00   ❤️ 1
    看有没有必要合并呗, 一般不是写的时候, 直接放在一起吗, 多打几个字,多写一个for 不麻烦吗?

    如果是新的需求, 则把循环放在一个新的方法里面
    MrEggNoodle
        3
    MrEggNoodle  
       2015-04-24 22:22:48 +08:00
    其实没所谓吧,各有各的代码习惯~除非公司做了限制。
    cfan8
        4
    cfan8  
       2015-04-24 22:23:32 +08:00
    楼主需要的是函数式编程,就不会有这种困扰了= =
    zhmin
        5
    zhmin  
    OP
       2015-04-24 22:27:39 +08:00
    @df4VW 感觉第二种效率也没想象中的高吧,还是取决于do_somthing_1和do_somthing_2的复杂度。
    最近接手同事的代码,第二种不好维护,往往一个for循环,里面的逻辑太多了,也不好拆分和维护
    zts1993
        6
    zts1993  
       2015-04-24 22:49:13 +08:00
    for item in items:
    process(item)




    def process(item):
    a()
    b()


    这样呢?
    ryd994
        7
    ryd994  
       2015-04-24 22:52:17 +08:00 via Android
    效率没区别啊………
    另外说不定编译器能优化掉呢?
    zipher
        8
    zipher  
       2015-04-24 22:53:33 +08:00
    基本都被编译器优化了
    哪种易读写哪种
    Hyperion
        9
    Hyperion  
       2015-04-24 23:22:07 +08:00   ❤️ 1
    会合并,就是因为不相关才放一起。

    循环合并会优化,楼上两位能否告知下相关资料地址?真不知道python会合并…

    >>> def test():
    ... items = ['cat', 'meow', 'dog', 'woof']
    ... for item in items:
    ... print item
    ... for item in items:
    ... print item

    >>> dis.dis(test.func_code)
    2 0 LOAD_CONST 1 ('cat')
    3 LOAD_CONST 2 ('meow')
    6 LOAD_CONST 3 ('dog')
    9 LOAD_CONST 4 ('woof')
    12 BUILD_LIST 4
    15 STORE_FAST 0 (items)

    3 18 SETUP_LOOP 19 (to 40)
    21 LOAD_FAST 0 (items)
    24 GET_ITER
    >> 25 FOR_ITER 11 (to 39)
    28 STORE_FAST 1 (item)

    4 31 LOAD_FAST 1 (item)
    34 PRINT_ITEM
    35 PRINT_NEWLINE
    36 JUMP_ABSOLUTE 25
    >> 39 POP_BLOCK

    5 >> 40 SETUP_LOOP 19 (to 62)
    43 LOAD_FAST 0 (items)
    46 GET_ITER
    >> 47 FOR_ITER 11 (to 61)
    50 STORE_FAST 1 (item)

    6 53 LOAD_FAST 1 (item)
    56 PRINT_ITEM
    57 PRINT_NEWLINE
    58 JUMP_ABSOLUTE 47
    >> 61 POP_BLOCK
    >> 62 LOAD_CONST 0 (None)
    65 RETURN_VALUE
    >>>
    ryd994
        10
    ryd994  
       2015-04-24 23:38:58 +08:00   ❤️ 1
    @Hyperion 抱歉没注意是python
    python的话就没这回事了
    Hyperion
        11
    Hyperion  
       2015-04-24 23:59:17 +08:00
    @ryd994 奥,了解,谢谢。
    secondwtq
        12
    secondwtq  
       2015-04-25 00:05:08 +08:00
    一般习惯性放到一个循环里,大概最主要原因是讨厌“冗余”的 for。不过实际上我遇到大多数情况里面感觉两个循环任务还是有一些区别的。

    如果是 Python 的话,我对其性能一直没有什么太大的好感,也并不希望能通过这种 trick 获得任何的提升。
    zhmin
        13
    zhmin  
    OP
       2015-04-25 00:28:12 +08:00
    @Hyperion 如果两者相关的话, 那怎么分离?
    mahone3297
        14
    mahone3297  
       2015-04-25 00:36:09 +08:00
    确实是个问题。
    为了可读性,我觉得分开比较好。。。
    zhmin
        15
    zhmin  
    OP
       2015-04-25 00:55:53 +08:00
    @Hyperion 我做了一个测试,

    1 def func_1(x):
    2 x += 1
    3
    4 def func_2(x):
    5 x += 1
    6
    7 def test_1():
    8 for i in range(100000):
    9 func_1(i)
    10 func_2(i)
    11
    12 def test_2():
    13 data = range(100000)
    14 for i in data:
    15 func_1(i)
    16 for i in data:
    17 func_2(i)
    18
    19 if __name__ == "__main__":
    20 import timeit
    21 print(timeit.timeit("test_1()",number=1000, setup="from __main__ import test_1"))
    22 print(timeit.timeit("test_2()",number=1000, setup="from __main__ import test_2"))

    仅仅就是简单自增,输出结果为
    31.7822570801
    31.4160778522

    看来即使编译器没优化, 但效率几乎没差别。
    如果是更加复杂的处理,估计效率差距会更少
    Hyperion
        16
    Hyperion  
       2015-04-25 00:57:35 +08:00
    @zhmin 具体情况具体看(这句话好万能…),一般不会考虑这么细,而且写的时候考虑这个也很麻烦。

    最后优化时候再考虑吧。

    比如两个操作引用了什么共同对象,而且操作上没交集,我还是会放一起。或者是循环的次数很庞大,能并就并了。

    实际工程经验较少,仅供参考。
    sivacohan
        17
    sivacohan  
       2015-04-25 01:12:03 +08:00 via Android
    两个写法表达的含义是不同的。
    第一个是对列表整体的操作。可以理解为复杂的推导式。

    第二个是对列表元素的操作,是对列表中每一个元素元素的基本操作。

    至于效率,我的问题是,你的热点真的在这吗?没测试,别空谈优化。
    chevalier
        18
    chevalier  
       2015-04-25 01:15:43 +08:00
    “代码是写给人看的,顺便也机器能跑”
    Hyperion
        19
    Hyperion  
       2015-04-25 02:21:44 +08:00
    @zhmin 理论上来说,JUMP_ABSOLUTE 次数越少当然是越好,不过跳转开销其实也并不多。分次执行,去掉gc 的影响,我这边测试下来。range(1000000) 测试1000次,合并也就好了那么一丢丢。

    合并:445.608458035
    分开:448.548615123

    但其实也没有什么太大的意义。

    话说#17 楼的理解反了吧?…
    Phoinikas
        20
    Phoinikas  
       2015-04-25 10:41:15 +08:00
    楼主你思路可能错了,你同事这么写的原因大概只是他觉得这样写可读性更高,而你的看法正好相反,这是没有标准的。

    从效率上来说,循环本身是不耗时的(可以忽略),耗时的是循环里面的操作,两种写法中do_something_1和do_something_2执行的总数都是一样,所以测试出来两种写法的耗时并无大的区别。
    notcome
        21
    notcome  
       2015-04-25 13:20:18 +08:00 via iPad
    Python 的循环怎么可能合并,你得先看有没有副作用啊。

    反正不追求速度,我觉得你爱怎么来怎么来。如果是我的话,我觉得合并的可读性较高,循环那一层在我看来是废话,而废话,能写一次就不要写两次。

    但在其它语言中,这确实是可以合并的,比如 Haskell。

    将一个列表里每一个元素加一,可以是:
    map (+1) list

    全平方,可以是
    map (^2) list

    或者写清楚一点,f = (+1),g = (^2)
    那么把一个表里所有数加一再平方,就是:
    map g (map f list)

    但是不用担心,编译器会避免遍历两次表的,上述代码会被优化成:
    map (g . f) list

    其中,点号代表函数……composition,中文啥来着?
    geeklian
        22
    geeklian  
       2015-04-26 11:55:18 +08:00 via iPhone
    怎么可读性高,怎么接近业务逻辑怎么来。

    这么点性能都纠结,干嘛不换java.netc++
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2717 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 05:30 · PVG 13:30 · LAX 22:30 · JFK 01:30
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.