RE Python no sigue este principio. En general, sigue el principio. Ejemplo básico:
>>> x = ['foo']
>>> x
['foo']
>>> x = (lambda: ['foo'])()
>>> x
['foo']
Sin embargo, Python define expresiones y declaraciones por separado. Dado que las if
ramas, los while
bucles, la asignación destructiva y otras declaraciones no se pueden usar en lambda
expresiones, la letra del principio de Tennent no se aplica a ellos. Aun así, restringirse a usar solo expresiones de Python todavía produce un sistema completo de Turing. Así que no veo esto como una violación del principio; o más bien, si viola el principio, entonces ningún lenguaje que defina declaraciones y expresiones por separado puede ajustarse al principio.
Además, si el cuerpo de la lambda
expresión capturara un rastro de la pila o realizara otra introspección en la máquina virtual, eso podría causar diferencias. Pero en mi opinión, esto no debe considerarse como una violación. Si expr
y (lambda: expr)()
necesariamente compila al mismo bytecode, entonces el principio realmente concierne a los compiladores, no a la semántica; pero si pueden compilar a diferentes bytes, no deberíamos esperar que el estado de la VM sea idéntico en cada caso.
Se puede encontrar una sorpresa usando la sintaxis de comprensión, aunque creo que esto tampoco es una violación del principio de Tennent. Ejemplo:
>>> [x for x in xrange(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [f() for f in [lambda: x for x in xrange(10)]] # surprise!
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
>>> # application of Tennent principle to first expression
... [(lambda: x)() for x in xrange(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [f() for f in [(lambda x: lambda: x)(x) for x in xrange(10)]] # force-rebind x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> map(lambda f:f(), map(lambda x: lambda: x, xrange(10))) # no issue with this form
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
La sorpresa es el resultado de cómo se definen las comprensiones de listas. La comprensión 'sorpresa' anterior es equivalente a este código:
>>> result = []
>>> for x in xrange(10):
... # the same, mutable, variable x is used each time
... result.append(lambda: x)
...
>>> r2 = []
>>> for f in result:
... r2.append(f())
...
>>> r2
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
Visto de esta manera, la comprensión 'sorpresa' anterior es menos sorprendente, y no una violación del principio de Tennent.
expr
obtiene el seguimiento de la pila actual.