代码之家  ›  专栏  ›  技术社区  ›  Tony Veijalainen

使用这个setitem函数来克服列表理解的局限性会非常不合意吗?

  •  2
  • Tony Veijalainen  · 技术社区  · 15 年前
    >>> a=range(5)
    >>> [a[i] for i in range(0,len(a),2)] ## list comprehension for side effects
    [0, 2, 4]
    >>> a
    [0, 1, 2, 3, 4]
    >>> [a[i]=3 for i in range(0,len(a),2)] ## try to do assignment
    SyntaxError: invalid syntax
    >>> def setitem(listtochange,n,value):  ## function to overcome limitation
        listtochange[n]=value
        return value
    
    >>> [setitem(a,i,'x') for i in range(0,len(a),2)] ## proving the function
    ['x', 'x', 'x']
    >>> a 
    ['x', 1, 'x', 3, 'x']   # We did assignment anyway
    
    4 回复  |  直到 15 年前
        1
  •  26
  •   Mark Byers    15 年前

    不要使用列表理解来执行副作用-那不是蟒蛇。改用显式循环:

    for i in range(0,len(a),2):
        a[i] = 3
    

    除了列表理解中的副作用令人惊讶和意外之外,您正在构建一个从不使用的结果列表,这是浪费的,在这里完全不必要的。

        2
  •  9
  •   kennytm    15 年前

    对。我建议使用

    a[::2] = ['x'] * len(a[::2])
    

    相反。


    编辑:

    python 2.6的微基准:

    ~:249$ python2.6 -m timeit -s 'a = range(2000)' 'a[::2] = [8] * len(a[::2])'
    10000 loops, best of 3: 26.2 usec per loop
    
    ~:250$ python2.6 -m timeit -s 'a = range(2000)' 'a[::2] = [8] * (len(a)/2)'
    10000 loops, best of 3: 19.6 usec per loop
    
    ~:251$ python2.6 -m timeit -s 'a = range(2000)' 'for i in xrange(0,len(a),2): a[i] = 8'
    10000 loops, best of 3: 92.1 usec per loop
    
    ~:252$ python2.6 -m timeit -s 'a = range(2000)
    > def assign(x,i,v):x[i]=v;return v' '[assign(a,i,8) for i in xrange(0, len(a), 2)]'
    1000 loops, best of 3: 336 usec per loop
    

    Python 3.1:

    ~:253$ python3.1 -m timeit -s 'a = list(range(2000))' 'a[::2] = [8] * len(a[::2])'
    100000 loops, best of 3: 19.8 usec per loop
    
    ~:254$ python3.1 -m timeit -s 'a = list(range(2000))' 'a[::2] = [8] * (len(a)//2)'
    100000 loops, best of 3: 13.4 usec per loop
    
    ~:255$ python3.1 -m timeit -s 'a = list(range(2000))' 'for i in range(0,len(a),2): a[i] = 8'
    10000 loops, best of 3: 119 usec per loop
    
    ~:256$ python3.1 -m timeit -s 'a = list(range(2000))
    > def assign(x,i,v):x[i]=v;return v' '[assign(a,i,8) for i in range(0, len(a), 2)]'
    1000 loops, best of 3: 361 usec per loop
    
        3
  •  3
  •   gilesc    15 年前

    您也可以使用 list.__setitem__

    a = range(5)
    [a.__setitem__(i,"x") for i in range(0,len(a),2)]
    

    或者,如果您希望避免构建中间列表:

    any(a.__setitem__(i,"x") for i in range(0,len(a),2))
    

    但清单理解中的任务确实是不合意的。

        4
  •  -1
  •   Community Mohan Dere    9 年前

    关于我提到的时间(另请参见 Improving pure Python prime sieve by recurrence formula ) 从时间导入时钟

    def rwh_primes1(n):
        # https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
        """ Returns  a list of primes < n """
        sieve = [True] * (n//2)
        for i in xrange(3,int(n**0.5)+1,2):
            if sieve[i//2]:
                sieve[i*i//2::i] = [False] * ((n-i*i-1)//(2*i)+1)
        return [2] + [2*i+1 for i in xrange(1,n/2) if sieve[i]]
    
    def rwh_primes_tjv(n):
        # recurrence formula for length by amount1 and amount2 tjv
        """ Returns  a list of primes < n """
        sieve = [True] * (n//2)
        amount1 = n-10
        amount2 = 6
    
        for i in range(3,int(n**0.5)+1,2):
            if sieve[i//2]:
                 ## can you make recurrence formula for whole reciprocal?
                sieve[i*i//2::i] = [False] * (amount1//amount2+1)
            amount1-=4*i+4
            amount2+=4
    
        return [2] + [2*i+1 for i in xrange(1,n//2) if sieve[i]]
    
    def rwh_primes_len(n):
        """ Returns  a list of primes < n """
        sieve = [True] * (n//2)
    
        for i in range(3,int(n**0.5)+1,2):
            if sieve[i//2]:
                sieve[i*i//2::i] = [False] * len(sieve[i*i//2::i])
    
        return [2] + [2*i+1 for i in xrange(1,n//2) if sieve[i]]
    
    def rwh_primes_any(n):
        """ Returns  a list of primes < n """
        halfn=n//2
        sieve = [True] * (halfn)
    
        for i in range(3,int(n**0.5)+1,2):
            if sieve[i//2]:
                any(sieve.__setitem__(item,False) for item in range(i*i//2,halfn,i))
    
        return [2] + [2*i+1 for i in xrange(1,n//2) if sieve[i]]
    
    
    if __name__ == "__main__":
        n = 1000000
    
        print("rwh sieve1")
        t=clock()
        r=rwh_primes1(n)
        print("Length %i,  %s ms" %(len(r),1000*(clock()-t)))
    
        print("rwh sieve with recurrence formula")
        t=clock()
        r=rwh_primes_tjv(n)
        print("Length %i,  %s ms" %(len(r),1000*(clock()-t)))
    
        print("rwh sieve with len function")
        t=clock()
        r=rwh_primes_len(n)
        print("Length %i,  %s ms" %(len(r),1000*(clock()-t)))
    
        print("rwh sieve with any with side effects")
        t=clock()
        r=rwh_primes_any(n)
        print("Length %i,  %s ms" %(len(r),1000*(clock()-t)))
        raw_input('Ready')
    
    """ Output:
    rwh sieve1
    Length 78498,  213.199442946 ms
    rwh sieve with recurrence formula
    Length 78498,  218.34143725 ms
    rwh sieve with len function
    Length 78498,  257.80008353 ms
    rwh sieve with any with side effects
    Length 78498,  829.977273648 ms
    Ready
    """
    

    长度函数和所有带有setitem的函数都不是令人满意的替代方法,但这里的计时是为了演示它。

    RWH筛 伦恩 功能 长度78498, 257.80008353毫秒

    RWH筛 任何 有副作用 长度78498, 829.977273648毫秒

    推荐文章