Próbuję wygenerować niekończący strumień wyników, biorąc pod uwagę funkcję F, a wartość początkowa x, więc pierwsze połączenie powinno dać wartość początkową, drugie połączenie powinno dać F (x), trzeci wywołanie jest f (x2), podczas gdy x2 jest poprzednim Wynik f (x) i tak dalej ..

Co wymyśliłem:

def generate(f, x): 
   return itertools.repeat(lambda x: f(x))

Który nie działa. jakieś pomysły? (Nie mogę używać wydajności w moim kodzie). Nie mogę również używać więcej niż 1 linia kodu tego problemu. wszelka pomoc byłaby doceniona.

Należy również pamiętać, że w poprzednim ex. Poproszono mnie o wykorzystanie wydajności. Bez problemów:

while True:
    yield x
    x = f(x)

To działa dobrze. Ale teraz .. nie ma pojęcia, jak to zrobić bez

1
David 27 listopad 2013, 21:09

3 odpowiedzi

Najlepsza odpowiedź

W Pythonie 3.3 możesz użyć itertools.accumulate:

import itertools

def generate(f, x):
  return itertools.accumulate(itertools.repeat(x), lambda v,_:f(v))

for i, val in enumerate(generate(lambda x: 2*x, 3)):
  print(val)
  if i == 10:
    break
4
NPE 27 listopad 2013, 17:28

Myślę, że to działa:

import itertools as it
def g(f, x):
    return it.chain([x],(setattr(g, 'x', f(getattr(g, 'x', x))) or getattr(g, 'x') for _ in it.count()))

def f(x):
    return x + 1

gen = g(f, 1)
print next(gen)
print next(gen)
print next(gen)
print next(gen)

Oczywiście polegają na niektórych szkicu zachowań, w którym faktycznie dodam atrybut do samej funkcji, aby zachować stan. Zasadniczo ta funkcja będzie działać tylko po raz pierwszy, kiedy to zadzwonisz. Po tym wszystkie zakłady są wyłączone.

Jeśli chcemy rozluźnić ten ograniczenie, możemy użyć tymczasowej przestrzeni nazw. Problem polega na tym, że uzyskanie tymczasowej przestrzeni nazw potrzebujemy unikalnej instancji klasy (lub klasy, ale instancja jest czyszczeniem i wymaga tylko 1 dodatkowego zestawu nawiasów). Aby to nastąpić w jednej linii, musimy utworzyć nową funkcję Inline i użyć tego jako domyślnego argumentu:

import itertools as it
def g(f, x):
    return (lambda f, x, ns=type('foo', (object,), {})(): \
        it.chain([x], 
                 (setattr(ns, 'x', f(getattr(ns, 'x', x))) or getattr(ns, 'x') 
                          for _ in it.count()))
            )(f, x)

def f(x):
    return x + 1

gen = g(f, 1)
print next(gen) == 1
print next(gen) == 2
print next(gen) == 3
print next(gen) == 4

print "first worked?"
gen2 = g(f, 2)
print next(gen2) == 2
print next(gen2) == 3
print next(gen2) == 4

Złamałem go na kilka linii, czytelności, ale jest to 1-liniowiec w sercu.

Wersja bez importu

(i najbardziej solidny, ale wierzę).

def g(f, x):
    return iter(lambda f=f, x=x, ns=type('foo', (object,), {'x':x}): ((getattr(ns, 'x'),setattr(ns, 'x', f(getattr(ns, 'x'))))[0]), object())

Jedna sztuczka tutaj jest taka sama jak wcześniej. Tworzymy funkcję Lambda z niezmiennym argumentem domyślnym, aby zachować stan. W funkcji budujemy krotkę. Pierwszym elementem jest to, czego właściwie chcesz, drugi element jest wartością zwracaną funkcji setattr, która służy do aktualizacji stanu. Aby pozbyć się itertools.chain, ustawić wartość początkowa na przestrzeni nazw do wartości x, więc klasa jest już zainicjowana, aby mieć stan wyjścia. Drugą sztuczką jest to, że używamy dwóch argumentów iter, aby pozbyć się it.count(), który był używany tylko do stworzenia nieskończonego. iter Wciąż wywołuje funkcję, którą nadajesz jako pierwszy argument, dopóki wartość zwracana jest równa drugiego argumentu. Jednakże, ponieważ mój drugi argument jest instancją object, nic zwracanego z naszej funkcji nigdy nie będzie równe, więc skutecznie stworzyliśmy nieskończoną iterable bez {x7}} lub yield! Przyjdź, by o tym pomyśleć, wierzę, że ta ostatnia wersja jest najbardziej solidna. Poprzednie wersje miały błąd, w którym polegali na prawdziwości zwracanej wartości f. Myślę, że mogliby się nie udać, jeśli zwrócił {{x10}} {{x11}}. Ta ostatnia wersja rozwiązuje ten błąd.

4
mgilson 27 listopad 2013, 18:16

Zgaduję, że jest to jakiś zadanie domowe lub zadanie? Jako taki, powiedziałbym, że powinienem spojrzeć na wyrażenia generatora . Chociaż zgadzam się z innymi komentatorami, że wydaje się to ćwiczenie wątpliwej wartości ...

0
Silas Ray 27 listopad 2013, 17:20