Python 3.6.1 preserves keyword order through cached calls
Python 3.6.1 corrects cache behavior for ordered keyword arguments and extends protocol consistency in the standard library.
A cache is correct only when its idea of equivalent calls matches the function it wraps. Python 3.6 preserves keyword argument order, so two calls with the same names and values can still convey different information. Python 3.6.1 corrects functools.lru_cache to preserve that distinction. The change is a useful example of a language guarantee requiring corresponding changes in library machinery that intercepts function calls.
The release page dates the update to March 21, 2017. The NEWS file in the release records issue 29203 as the cache correction. It explicitly says that f(a=1, b=2) and f(b=2, a=1) now receive separate cached results because those calls can produce different answers. A wrapper that erased the distinction could return a result computed for a different ordering.
I appreciate Python most when its protocols compose predictably. A function decorator should preserve the behavior that makes the wrapped function meaningful. This fix matters because the function can be correct in isolation while a cache changes its externally visible result.
Keyword order belongs to the call
Consider a function that exposes the order of its keyword arguments. The example below makes the information observable without depending on any external service or mutable global state.
from functools import lru_cache
@lru_cache(maxsize=16)
def field_order(**fields):
return tuple(fields)
assert field_order(a=1, b=2) == ("a", "b")
assert field_order(b=2, a=1) == ("b", "a")
The NEWS entry ties the correction to PEP 468, the keyword-order change already included in Python 3.6. The relevant property is visible in the returned tuple. Swapping the keyword arguments changes that tuple, even though looking up either individual name would return the same value in both calls. A cache must account for all the call information that can affect the result.
Separate entries also mean that applications cannot assume differently ordered keyword calls share a cache entry. A function whose own behavior ignores the order may still receive the same logical inputs through different calling forms. The interpreter cannot infer that application's equivalence rule from the function signature. Preserving the caller's ordering avoids discarding information before the function has a chance to interpret it.
The same maintenance release fixes a different lru_cache problem in its C implementation. Issue 28969 describes a race when threads call a fully populated cache with the same arguments that are not yet cached. The failure could raise KeyError. This correction concerns concurrent cache bookkeeping, while issue 29203 concerns the information represented by a call. Both affect code that delegates behavior to a decorator around an otherwise ordinary function.
Filesystem objects reach another library interface
Issue 29623 allows a path-like object as the single argument to ConfigParser.read(). Python 3.6 already introduces the filesystem path protocol, as the release page records through PEP 519. The maintenance change extends that protocol's use in a standard-library method where the caller is supplying a configuration-file location.
A protocol becomes useful across a program when receiving APIs recognize it consistently. Otherwise an object that represents a path still needs local conversions at individual call sites. That requirement leaks knowledge of the receiving library into code whose actual concern is identifying a file. The ConfigParser correction removes one such mismatch without introducing a different configuration format.
The distinction between one path-like argument and an arbitrary collection of inputs matters. The NEWS entry specifically describes acceptance of a path-like object as the single argument. It does not announce a general rewrite of configuration loading or claim that all methods in the library accept every object that resembles a pathname. The improvement has a concrete boundary.
An f-string remains an expression
The release also tightens the handling of formatted string literals. Issue 28739 says f-string expressions are no longer accepted as docstrings or by ast.literal_eval(), including f-strings that contain no expressions. That last case makes the correction more interesting than simply rejecting an interpolation that obviously needs evaluation.
An f-string without a replacement field may look equivalent to a literal string when read as text. Its syntactic category still matters to tools deciding whether source is a literal. Accepting it because the current contents happen to need no interpolation would make that boundary depend on the contents of one particular expression. The fix makes the documented distinction in the NEWS apply even to that superficially simple case.
I prefer these explicit boundaries in a language whose libraries rely so heavily on implicit dispatch. Protocol support should be consistent where it is promised, while tools that accept restricted syntax need a dependable account of that restriction. Both properties help explain a program without relying on accidental behavior in its first implementation.
The final release includes changes after its candidate, notably issue 29723 on initializing sys.path for execution from an import location such as a zipfile or directory. The NEWS says the interpreter avoids adding that location's parent directory and avoids modifying unrelated path entries during insertion. Together with the cache correction, this is maintenance of behavior that sits between user code and the machinery executing it. The patch keeps those intermediaries consistent with the information and locations the caller actually supplied.