RE Python nie przestrzega tej zasady. Ogólnie rzecz biorąc, działa zgodnie z zasadą. Podstawowy przykład:
>>> x = ['foo']
>>> x
['foo']
>>> x = (lambda: ['foo'])()
>>> x
['foo']
Jednak Python definiuje wyrażenia i instrukcje osobno. Ponieważ if
rozgałęzień, while
pętli, destrukcyjnego przypisania i innych instrukcji nie można w ogóle używać w lambda
wyrażeniach, litera zasady Tennent nie ma do nich zastosowania. Mimo to ograniczenie się do używania tylko wyrażeń w języku Python nadal powoduje utworzenie pełnego systemu Turinga. Dlatego nie uważam tego za naruszenie zasady; a raczej, jeśli narusza zasadę, żaden język, który definiuje oświadczenia i wyrażenia osobno, nie może być zgodny z tą zasadą.
Ponadto, jeśli treść lambda
wyrażenia przechwytuje ślad stosu lub wykonuje inne introspekcje w maszynie wirtualnej, może to powodować różnice. Ale moim zdaniem nie powinno to być traktowane jako naruszenie. Jeśli expr
i (lambda: expr)()
koniecznie kompiluje się do tego samego kodu bajtowego, wówczas zasada naprawdę dotyczy kompilatorów, a nie semantyki; ale jeśli można je skompilować do innego kodu bajtowego, nie należy oczekiwać, że stan maszyny wirtualnej będzie identyczny w każdym przypadku.
Przy użyciu składni rozumowania można spotkać niespodziankę, chociaż uważam, że nie jest to również naruszenie zasady Tennent. Przykład:
>>> [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]
Zaskoczenie wynika z tego, jak definiowane są wyrażenia listowe. Powyższe rozumienie „niespodzianki” jest równoważne z tym kodem:
>>> 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]
Patrząc w ten sposób powyższe rozumienie „niespodzianki” jest mniej zaskakujące i nie stanowi naruszenia zasady Tennent.