I don’t think this is fundamentally different from what it’s already doing when it reloads a module: it looks for a specially-named attribute (__name__
), which is a string specifying a module name, and guesses that importing that name will re-create a module that is conceptually the same as the module that was passed in.
That can, in principle, be defeated: create and import a module; then manipulate sys.path
such that a different .py
file with the same name will be found first; then modify the original module and attempt to reload
it. Instead of seeing the changes to the original code, the module gets entirely replaced with the other one that was found instead.
It’s true that the __name__
of a function might not match the variable name passed to importlib.reload
- but this happens because the function was aliased locally. The original __name__
value should, clearly, be used - it’s not as if anyone is in the habit of reassigning that (although they can, and should bear the consequences).
It’s also true - as I pointed out earlier - that not everything has a __name__
, and that import
syntax allows for “importing” any arbitrary attribute from a module, which might have any arbitrary type. However, I think catching the resulting AttributeError
and converting it to an ImportError
ought to be enough for these circumstances. “You can’t always get a meaningful result” isn’t a reason for not, pardon the pun, try
ing to implement some functionality.
However, there is another complication here. As I said, the import
syntax allows for “importing” any arbitrary attribute from a module, which might have any arbitrary type. Including, you know, module
. Which is how importing a module from a package works: packages are modules, and a module in a package is an attribute of that package.
That would cause an ambiguity, or at least an inconsistency, with the proposal. Suppose we previously did from foo import bar
, and then attempt importlib.reload(bar)
. If we first check whether bar
is a module (like with the current code), we would simply re-load the bar
module directly (and reassign it as an attribute of the foo
package). However, if bar
isn’t a module, we would necessarily have to reload foo
; and some might therefore expect foo
to be reloaded even if bar
is a module.
“Explicit is better than implicit”, and “special cases aren’t special enough to break the rules”. it makes more sense to have code that’s clear and consistent about what needs to be imported.
Regarding the original example:
In fact, we almost have it already: myfunction = importlib.reload(mymodule).myfunction
. I think that’s probably the best option here: it’s clear what’s going on, and it avoids using an extra import
statement after the code has already been imported, simply to bind a name.
It does repeat the myfunction
name still, but that’s a separate proposal…