Jak działa zrozumienie lambda/wydajność/generator?
Przeglądałem dzisiaj mój kod i znalazłem to:
def optionsToArgs(options, separator='='):
kvs = [
(
"%(option)s%(separator)s%(value)s" %
{'option' : str(k), 'separator' : separator, 'value' : str(v)}
) for k, v in options.items()
]
return list(
reversed(
list(
(lambda l, t:
(lambda f:
(f((yield x)) for x in l)
)(lambda _: t)
)(kvs, '-o')
)
)
)
Wydaje się, że pobiera dict parametrów i zamienia je w listę parametrów dla polecenia powłoki. Wygląda na to, że wykorzystuje wydajność wewnątrz generatora, co wydawało mi się niemożliwe...?
>>> optionsToArgs({"x":1,"y":2,"z":3})
['-o', 'z=3', '-o', 'x=1', '-o', 'y=2']
Jak to działa? 2 answers
Od wersji Python 2.5, yield <value>
jest wyrażeniem, a nie instrukcją. Zobacz PEP 342 .
Kod jest ohydny i niepotrzebnie brzydki, ale jest legalny. Jego centralnym trikiem jest użycie f((yield x))
wewnątrz wyrażenia generatora. Oto prostszy przykład tego, jak to działa:
>>> def f(val):
... return "Hi"
>>> x = [1, 2, 3]
>>> list(f((yield a)) for a in x)
[1, 'Hi', 2, 'Hi', 3, 'Hi']
Zasadniczo, użycie yield
w wyrażeniu generatora powoduje, że generuje on dwie wartości dla każdej wartości w źródle iterowalnym. Gdy wyrażenie generatora jest powtarzane nad listą łańcuchów, na każdym iteracja, yield x
najpierw daje ciąg znaków z listy. Wyrażeniem docelowym genexp jest f((yield x))
, więc dla każdej wartości na liście "wynik" wyrażenia generatora jest wartością f((yield x))
. Ale f
po prostu ignoruje swój argument i zawsze zwraca ciąg opcji "-o"
. Tak więc na każdym kroku generowania generuje najpierw łańcuch klucz-wartość (np. "x=1"
), a następnie "-o"
. Zewnętrzny list(reversed(list(...)))
tworzy listę z tego generatora, a następnie odwraca ją tak, że "-o"
S będzie przyjdź przed każdą opcją zamiast po.
kvs = [...] # same list comprehension can be used for this part
result = []
for keyval in kvs:
result.append("-o")
result.append(keyval)
return result
Nawet jeśli lubisz zwięzły," sprytny " Kod, możesz po prostu zrobić
return sum([["-o", keyval] for keyval in kvs], [])
Samo rozumienie listy jest dziwaczną mieszanką próbnej czytelności i nieczytelności. Jest to po prostu napisane:
kvs = [str(optName) + separator + str(optValue) for optName, optValue in options.items()]
Powinieneś rozważyć zorganizowanie "interwencji" dla ktokolwiek umieścił to w Twojej bazie kodowej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-11 18:42:53
O Boże. W zasadzie sprowadza się to do tego:
def f(_): # I'm the lambda _: t
return '-o'
def thegenerator(): # I'm (f((yield x)) for x in l)
for x in kvs:
yield f((yield x))
Więc gdy iteracja jest skończona, Generator daje x
(członek kvs
), a następnie wartość zwracaną f
, która jest zawsze -o
, wszystko w jednej iteracji nad kvs
. Cokolwiek yield x
zwróci i co zostanie przekazane f
jest ignorowane.
Odpowiedniki:
def thegenerator(): # I'm (f((yield x)) for x in l)
for x in kvs:
whatever = (yield x)
yield f(whatever)
def thegenerator(): # I'm (f((yield x)) for x in l)
for x in kvs:
yield x
yield f(None)
def thegenerator(): # I'm (f((yield x)) for x in l)
for x in kvs:
yield x
yield '-o'
Istnieje wiele sposobów, aby zrobić to znacznie prostsze, oczywiście. Nawet z oryginalną sztuczką z podwójną wydajnością, cała rzecz mogła być
return list(((lambda _: '-o')((yield x)) for x in kvs))[::-1]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-26 19:36:35