On Wed, May 23, 2012 at 12:51 AM, Eric V. Smith email@example.com wrote:
That seems like a pretty convincing example to me.
Personally I'm +1 on putting dynamic computation into the PEP, at least for top-level namespace packages, and probably for all namespace packages.
Same here, but Guido's right that the rationale (and example) should be clearer in the PEP itself if the feature is to be retained.
P.S.: Here's the current code in the pep-420 branch. This code still has the restriction that sys.path (or parent_path in general) can't be replaced. I'll fix that if we decide to keep the feature.
I wonder if it would be worth exposing an importlib.LazyRef API to make it generally easy to avoid this kind of early binding problem?
class LazyRef: # similar API to weakref.weakref def __init__(self, modname, attr=None): self.modname = modname self.attr = attr def __call__(self): mod = sys.modules[self.modname] attr = self.attr if attr is None: return mod return getattr(mod, attr)
Then _NamespacePath could just be defined as taking a callable that returns the parent path:
class _NamespacePath: def __init__(self, name, path, parent_path, path_finder): self._name = name self._path = path self._parent_path = parent_path self._last_parent_path = tuple(parent_path) self._path_finder = path_finder
def _recalculate(self): # If _parent_path has changed, recalculate _path parent_path = tuple(self._parent_path()) # Retrieve and make a copy if parent_path != self._last_parent_path: loader, new_path = self._path_finder(self._name, parent_path) # Note that no changes are made if a loader is returned, but we # do remember the new parent path if loader is None: self._path = new_path self._last_parent_path = parent_path # Save the copy return self._path
Even if the LazyRef idea isn't used, I still like the idea of passing a callable in to _NamespacePath for the parent path rather than hardcoding the "module name + attribute name" approach.