2015-10-17 16 views
6

Program poniżej [Python 3.4] jest prosty Eratosthenes sitowa:Generatory Pythona; dwa, takie same programy działają odmiennie

from itertools import * 
def excl(ns,pr): 
    return (i for i in ns if i%pr) 
def sieve(ns): 
    while True: 
     pr=next(ns) 
     yield pr 
     ns=excl(ns,pr) 
     # ns=(i for i in ns if i%pr) 
r=list(islice(sieve(count(2)),10)) 

która produkuje [2, 3, 5, 7, 11, 13, 17, 19, 23, 29 ]. OK. Odkomentowanie linii, która włącza excl() i komentowanie wywołania, daje [2, 3, 4, 5, 6, 7, 8, 9, 10, 11]. Czemu?

Czy jest to związane z problemami oczekiwanymi podczas modyfikowania sekwencji wewnątrz pętli, która wykonuje iteracje?

Dziękuję za podpowiedź.

Odpowiedz

2

Twoim problemem jest to, że pr mowa wyrażeniem generatora jest samo pr które można modyfikować w następnej iteracji swojej pętli while, więc każdy numer, który nie jest podzielna przez poprzednie „prime” liczba jest traktowana jako "główny". Który sam modyfikuje pr i tak dalej. W funkcji excl, pr, które odnoszą się do jest przekazywane jako argument, który nigdy się nie zmienia.

+0

Nie jestem pewien, czy rozumiem tę odpowiedź. Prime pr nie zmienia się w excl (ani w gen.expression), zmienia się w pętli, a ten kontekst jest identyczny dla wersji inlined i "call". BTW Usunąłem błędną uwagę na temat filtra(). –

+0

@JerzyKarczmarczuk Według [PEP 227] (https://www.python.org/dev/peps/pep-0227/), jeśli nazwa jest używana w bloku kodu (funkcja zagnieżdżona), ale nie jest tam związana i nie jest deklarowany globalnie, użycie jest traktowane ** jako odniesienie do ** najbliższego otaczającego obszaru funkcji. Jeśli chodzi o twoją sprawę, wyrażenie generatora jest funkcją pod maską i nie definiuje zmiennej "pr", więc jej 'pr' jest ** referencją ** do' pr' w funkcji otaczającej ('sito'). Co oznacza, że ​​gdy zmienia się słowo "pr" w 'sicie', to również' pr' w wyrażeniu generatora. – ppperry