Pergunta

O seguinte teste falhar:

#!/usr/bin/env python
def f(*args):
    """
    >>> t = 1, -1
    >>> f(*map(lambda i: lambda: i, t))
    [1, -1]
    >>> f(*(lambda: i for i in t)) # -> [-1, -1]
    [1, -1]
    >>> f(*[lambda: i for i in t]) # -> [-1, -1]
    [1, -1]
    """
    alist = [a() for a in args]
    print(alist)

if __name__ == '__main__':
    import doctest; doctest.testmod()

Em outras palavras:

>>> t = 1, -1
>>> args = []
>>> for i in t:
...   args.append(lambda: i)
...
>>> map(lambda a: a(), args)
[-1, -1]
>>> args = []
>>> for i in t:
...   args.append((lambda i: lambda: i)(i))
...
>>> map(lambda a: a(), args)
[1, -1]
>>> args = []
>>> for i in t:
...   args.append(lambda i=i: i)
...
>>> map(lambda a: a(), args)
[1, -1]
Foi útil?

Solução

Eles são diferentes, porque o valor de i tanto no gerador de expressão ea lista comp são avaliados preguiçosamente, ou seja, quando as funções anônimas são invocados em f.
Por esse tempo, i está vinculado ao último valor se t, que é -1.

Então, basicamente, é isso que a compreensão da lista faz (da mesma forma para o genexp):

x = []
i = 1 # 1. from t
x.append(lambda: i)
i = -1 # 2. from t
x.append(lambda: i)

Agora, os lambdas levar em torno de um fecho que as referências i, mas i é obrigado a -1 em ambos os casos, porque esse é o último valor que foi atribuído a.

Se você quiser ter certeza de que o lambda recebe o valor atual de i, faça

f(*[lambda u=i: u for i in t])

Desta forma, você forçar a avaliação de i no momento do encerramento é criado.

Editar : Existe uma diferença entre o gerador de expressões e list comprehensions:. O último vazamento a variável de contagem no âmbito circundante

Outras dicas

As variáveis ??capta lambda, não valores, daí o código

lambda : i

sempre retornará o valor i é atualmente obrigado a no fechamento. No momento em que é chamado, esse valor foi definido para -1.

Para obter o que deseja, você vai precisar para capturar o real vinculativo no momento do lambda é criado, por:

>>> f(*(lambda i=i: i for i in t)) # -> [-1, -1]
[1, -1]
>>> f(*[lambda i=i: i for i in t]) # -> [-1, -1]
[1, -1]

Expression f = lambda: i é equivalente a:

def f():
    return i

Expression g = lambda i=i: i é equivalente a:

def g(i=i):
    return i

i é um variável livre no primeiro caso, e é ligado ao parâmetro função no segundo caso, isto é, é uma variável local, nesse caso. Os valores para os parâmetros padrão são avaliados no momento da definição da função.

gerador de expressão é o escopo mais próxima envolvente (onde i é definido) para o nome i na expressão lambda, portanto i é resolvido pelo facto de bloco:

f(*(lambda: i for i in (1, -1)) # -> [-1, -1]

i é uma variável local do bloco lambda i: ..., por conseguinte, o objecto que se refere é definida no referido bloco:

f(*map(lambda i: lambda: i, (1,-1))) # -> [1, -1]
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top