python reload()没有任何影响?

时间:2014-10-22 21:39:29

标签: python module

我在pyspark目录中有一个hbase.py文件。在REPL中我尝试重新加载它:

>>> reload(pyspark.hbase)
<module 'pyspark.hbase' from '/shared/hwspark2/python/pyspark/hbase.py'>
>>> from pyspark.hbase import *
>>> # run the code .. latest changes not apparent..

没有错误..但是,类的定义没有更新 - 正如新的印刷语句没有出现所证明的那样。

退出解释器并重新加载模块后,可以看到更新。然而,即使在重新加载后,模块的任何进一步更改也都不可见。

2 个答案:

答案 0 :(得分:2)

问题并不完全清楚,但我认为你误解了reload的所作所为。

它重新导入模块,包括其中定义的所有新类对象,并更改sys.modules[name]以引用该新模块对象,并将名称复制到您的全局变量。

但它确实全部。它不会自动查找旧模块的每个引用,更不用说旧模块中定义的任何内容等,并将它们全部修复以引用替换版本。 (怎么可能呢?在新模块中甚至可能没有 替换版本。就此而言,如果您的值由旧代码计算并且将以不同方式计算,它会有什么重新运行自导入模块以来您完成的所有事情。)

文档(上面链接的)以不同的术语解释它,但让我们具体化,所以我可以更直接地解释它。

创建此文件:

# mod.py
class Spam(object):
    def eggs(self):
        print('spam spam spam spam')

现在:

$ python
>>> import mod
>>> spam = mod.Spam()
>>> spam.eggs()
spam spam spam spam

现在让我们编辑它:

# mod.py
class Spam(object):
    def eggs(self):
        print('out of spam!!!')

>>> reload(mod)
>>> spam.eggs()
spam spam spam spam
>>> morespam = mod.Spam()
>>> morespam.eggs()
out of spam!!!
>>> type(spam) is type(morespam)
False

当您通过调用spam创建mod.Spam()时,会在全局变量中查找'mod',然后在生成的模块中查找'Spam',然后调用其构造函数和初始化程序,为您提供一个__class__是对该mod.Spam类的引用的对象。

当您致电spam.eggs()时,Python在全局词典中查找'spam',在'eggs'对象的词典中查找spam,然后失败,在'eggs'对象的字典中查找spam.__class__。我们知道,这是mod.Spam对象,它有一个eggs方法,因此会被调用。

现在,在我们reload(mod)之后,有一个名为'mod'的新对象,它有一个名为'Spam'的新类作为成员。但旧的modmod.Spam对象 - 以及您的spam仍然存在。现有的spam仍然引用其mod.Spam中的旧__class__。所以,当你第二次打电话给spam.eggs()时,事情就像以前一样。 Python将'spam'查找为全局,在'eggs'中首先查找spam,然后在spam.__class__中查找与之前相同的类,并调用与之前相同的函数。

当我们再次调用morespam来构建mod.Spam()时,现在在全局变量中查找'mod'并找到新的'mod'。然后它在该模块中查找'Spam'并找到新类。因此,我们有一个__class__是新mod.Spam的实例。当我们调用它的eggs方法时,同样的事情发生在上面,但现在它被调用的新函数。


使用from mod import *代替import mod会让事情变得难以理解,但基本思路是一样的。 from mod import *不会将mod放入您的全局变量中,而是复制所有非私有全局变量(mod.__all__中列出的任何内容,或者,如果不存在任何此类事物,则为在mod中,不以单个下划线开头)到您的全局变量。因此,reload创建一个新的模块对象,第二个from mod import *将所有新模块的非私有全局变量复制到您的全局变量中,替换旧的变量。但是,您的spam实例仍然是旧Spam的实例,而不是新实例。

答案 1 :(得分:1)

我想到了三种可能性(一种是@ abarnert&#39; s):

  • pyspark.hbase__all__,您尝试使用的课程不在其中
  • pyspark.hbase没有__all__,但您的班级名称/职能/等等以_开头。
  • 重新加载后你没有重新创建类实例,因此它们仍然与旧模块的类绑定。

__all__用作模块定义其官方API的方式。它还用于提供在发出from ... import *时要导入的名称列表。如果未定义__all__,则在该模块上使用_时,将加载模块中不以from ... import *开头的任何名称。

无论是否定义__all__,您都可以通过直接请求明确加载模块中定义的任何名称:

from xyz import _private

会将_private加载到您模块的命名空间中。