2015-03-11 6 views
6

Я написал простое правое сито (неограниченное сито Eratosthenes) с использованием Python, но по какой-то причине он работает неправильно. Вот сито:Создание простого простого сита в Python

from itertools import count 

def sieve(): 
    nums = count(2) 
    while True: 
     n = next(nums) 
     nums = filter(lambda k: k%n != 0, nums) 
     yield n 

К сожалению, это не работает. Вместо этого он просто возвращает те же значения, что и итератор count (2).

Для сравнения, это:

nums = count(2) 
print(next(nums)) 
nums = filter(lambda k: k%2 != 0, nums) 
print(next(nums)) 
nums = filter(lambda k: k%2 != 0, nums) 
print(next(nums)) 

напечатает:

2 
3 
5 

в то время как функция решето будет печатать:

Я думал, что вопрос был с странным поведением ягненка Питона а, но заменяя эту линию:

nums = filter(lambda k: k%n != 0, nums) 

с:

def f(k): return k%n != 0 
nums = filter(f, nums) 

не решает проблему.

+3

[Это не сито Эратосфена.] (Https://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf) – Veedrac

+0

Действительно интересная статья, спасибо! – IncongruentModulo1

ответ

7

Проблема заключается в том, что lambda всегда ссылаясь на значение последнее из n, а не один используется, когда lambda была создана. Самый простой способ вокруг него, чтобы захватить значение явно с помощью ключевого слова аргумент:

from itertools import count 

def sieve(): 
    nums = count(2) 
    while True: 
     n = next(nums) 
     nums = filter(lambda k, n=n: k%n != 0, nums) 
     yield n 

Это Python Гоча является well-documented в various StackOverflow answers. Справедливости ради следует, что такое же поведение разделяют и другие языки с лексическими замыканиями, такие как JavaScript и Common Lisp.

Возможно, это было связано с «странным поведением Python лямбда» в вопросе, хотя это поведение не имеет ничего общего с lambda, но с тем, что замыкание действительно фиксирует при обращении к изменяемой переменной - в Python, JavaScript и Common Lisp он фиксирует последнее значение переменной, тогда как в Scheme он фиксирует значение переменной, как это было в момент создания закрытия.

+0

Я думаю, что этот ответ велик, однако мне пришлось использовать 'ifilter', а не' filter', чтобы заставить его работать. Это ожидалось? С 'filter', похоже, он висит. Я нахожусь на python 2.7, что может быть актуальным. Генерация простых чисел является действительно опрятной идеей. –

+1

@JRichardSnape Да, OP использует Python 3, где 'filter' ленив и эквивалентен' itertools.ifilter' в Python 2. Фильтр Python 2 's' нетерпелив и быстро тратит всю доступную память, пытаясь построить бесконечный список , – user4815162342

Смежные вопросы