Deleted a module's function on interactive. Ho

2019-02-18 15:37发布

I've deleted a (package builtin) function on ipython:

Python 3.6.4 |Anaconda custom (64-bit)| (default, Jan 16 2018, 10:22:32) [MSC v.1900 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 6.2.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import math

In [2]: math.cos(0)
Out[2]: 1.0

In [3]: del math.cos

In [4]: math.cos(0)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-4-9cdcc157d079> in <module>()
----> 1 math.cos(0)

AttributeError: module 'math' has no attribute 'cos'

OK. But how do I reload the function? This didn't help:

In [5]: import importlib

In [6]: importlib.reload(math)
Out[6]: <module 'math' (built-in)>

In [7]: math.cos(0)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-7-9cdcc157d079> in <module>()
----> 1 math.cos(0)

AttributeError: module 'math' has no attribute 'cos'

2条回答
别忘想泡老子
2楼-- · 2019-02-18 16:10

OK people, I wrote a little module to solve this confusion. I sincerely doubt that it is buggless. So improvements are welcome.

This module works nicely both on Py 2 and 3. Tried on Python 2.7 and Python 3.5.



# rld.py --> the reloading module

import sys

__all__ = ["reload"]

try:
    # Python 2:
    _reload = reload
    from thread import get_ident
    def reload (module):
        if isinstance(module, basestring):
            module = sys.modules[module]
        if module.__name__==__name__:
            raise RuntimeError("Reloading the reloading module is not supported!")
        print ("Reloading: %s" % module.__name__)
        # Get locals() of a frame that called us:
        ls = sys._current_frames()[get_ident()].f_back.f_locals
        # Find variables holding the module:
        vars = [name for name, mod in ls.iteritems() if mod==module]
        if len(vars)==0:
            print ("Warning: Module '%s' has no references in this scope.\nReload will be attempted anyway." % module.__name__)
        else:
            print("Module is referenced as: %s" % repr(vars))
        # Reload:
        m = _reload(module)
        for x in vars:
            ls[x] = m
        print("Reloaded!")
except NameError:
    # Python 3:
    from _thread import get_ident
    def reload (module):
        if isinstance(module, str):
            module = sys.modules[module]
        if module.__name__==__name__:
            raise RuntimeError("Reloading the reloading module is not supported!")
        print ("Reloading: %s" % module.__name__)
        # Get locals() of a frame that called us:
        ls = sys._current_frames()[get_ident()].f_back.f_locals
        # Find variables holding the module:
        vars = [name for name, mod in ls.items() if mod==module]
        if len(vars)==0:
            print ("Warning: Module '%s' has no references in this scope.\nReload will be attempted anyway." % module.__name__)
        else:
            print("Module is referenced as: %s" % repr(vars))
        # Dereference all detected:
        for x in vars:
            del ls[x]
        del sys.modules[module.__name__]
        # Reimport:
        m = __import__(module.__name__)
        # Rebind to old variables:
        for x in vars:
            ls[x] = m
        # Remap references in the old module
        # to redirect all other modules that already imported that module:
        for vname in dir(m):
            setattr(module, vname, getattr(m, vname))
        print("Reloaded!")

>>> # Usage:
>>> from rld import * # Always import it first - just in case
>>> import math
>>> math.cos
<built-in function cos>
>>> del math.cos
>>> math.cos
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'cos'
>>> reload(math)
Reloading: math
Module is referenced as: ['math']
Reloaded!
>>> math.cos
<built-in function cos>
>>> #-------------------------
>>> # This also works:
>>> import math as quiqui
>>> alias = quiqui
>>> del quiqui.cos
>>> quiqui.cos
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'cos'
>>> alias.cos
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'cos'
>>> reload("math")
Reloading: math
Module is referenced as: ['alias', 'quiqui']
>>> quiqui.cos
<built-in function cos>
>>> alias.cos
<built-in function cos>

查看更多
劫难
3楼-- · 2019-02-18 16:17

The above code works for me in Python 3.4 on Windows but the documentation for 3.6 states:

Beware though, as if you keep a reference to the module object, invalidate its cache entry in sys.modules, and then re-import the named module, the two module objects will not be the same. By contrast, importlib.reload() will reuse the same module object, and simply reinitialise the module contents by rerunning the module’s code.

(so maybe I was only "lucky")

so what is pretty sure to work is:

import math,sys
del math.cos
del math
sys.modules.pop("math")   # remove from loaded modules
import math
print(math.cos(0))

It still works, and you don't even need reload. Just remove from cache & import again.

As noted in comments, using reload also works, but you need to update the module reference given by reload, not just reuse the same old one with the cos entry missing:

import math,sys
del math.cos
import importlib
math = importlib.reload(math)
print(math.cos(0))
查看更多
登录 后发表回答