【问题标题】:How does one do the equivalent of "import * from module" with Python's __import__ function?如何使用 Python 的 __import__ 函数执行相当于“import * from module”的操作?
【发布时间】:2008-09-29 04:28:41
【问题描述】:

给定一个带有模块名称的字符串,你如何导入模块中的所有内容,就好像你已经调用了:

from module import *

即给定字符串 S="module",如何获得以下等效项:

__import__(S, fromlist="*")

这似乎没有按预期执行(因为它没有导入任何内容)。

【问题讨论】:

    标签: python python-import


    【解决方案1】:

    请重新考虑。唯一比import *更糟糕的是magicimport *

    如果你真的想:

    m = __import__ (S)
    try:
        attrlist = m.__all__
    except AttributeError:
        attrlist = dir (m)
    for attr in attrlist:
        globals()[attr] = getattr (m, attr)
    

    【讨论】:

    • @John Millikin:但是如果一个模块定义了 all 你应该观察它
    • 学究起来,如果没有all,则只导入不以_开头的名称。
    • 你是对的:它令人发指、邪恶……而且非典型。我问的原因不是包含任何常规的 Python 模块,而是包含一组更改的短配置模块中的一个,特定于正在使用的计算机(没有定义 all,顺便)。我正在围绕这个进行重构。 :)
    • @BMH:您是否考虑过像 Django 中使用的设置聚合器?定义一个存储要搜索的模块列表的对象,然后覆盖 getattr 以使用 getattr() 执行对它们的搜索。
    • 是的,绝对没有理由为什么每个设置都应该存在于全局命名空间中,即options.some_option 显然优于some_option。您还可以在特定情况下在模块的字典上使用 dict.update()
    【解决方案2】:

    这是我为 Django 动态命名本地设置文件的解决方案。请注意下面添加的检查以不包括导入文件中包含“__”的属性。 __name__ 全局被本地设置文件的模块名称覆盖,导致在 manage.py 中使用的 setup_environ() 出现问题。

    try:
        import socket
        HOSTNAME = socket.gethostname().replace('.','_')
        # See http://docs.python.org/library/functions.html#__import__
        m = __import__(name="settings_%s" % HOSTNAME, globals=globals(), locals=locals(), fromlist="*")
        try:
            attrlist = m.__all__
        except AttributeError:
            attrlist = dir(m)        
        for attr in [a for a in attrlist if '__' not in a]:
            globals()[attr] = getattr(m, attr)
    
    except ImportError, e:
        sys.stderr.write('Unable to read settings_%s.py\n' % HOSTNAME)
        sys.exit(1)
    

    【讨论】:

      【解决方案3】:

      根本问题是我正在开发一些 Django,但在不止一台主机(与同事)上,所有主机都具有不同的设置。我希望在 project/settings.py 文件中做这样的事情:

      from platform import node
      
      settings_files = { 'BMH.lan': 'settings_bmh.py", ... } 
      
      __import__( settings_files[ node() ] )
      

      这似乎是一个简单的解决方案(因此很优雅),但我同意它有一种味道,并且当您必须使用 John Millikin 发布的逻辑(谢谢)时,这种简单性就会消失。这基本上是我采用的解决方案:

      from platform import node
      
      from settings_global import *
      
      n = node()
      
      if n == 'BMH.lan':
        from settings_bmh import *
      # add your own, here...
      else:
        raise Exception("No host settings for '%s'. See settings.py." % node())
      

      这对我们的目的很有效。

      【讨论】:

        【解决方案4】:

        在您的情况下,您似乎也可以在模块的字典中使用 dict.update()

        config = [__import__(name) for name in names_list]
        
        options = {}
        for conf in config:
            options.update(conf.__dict__)
        

        更新:我认为它有一个简短的“功能”版本:

        options = reduce(dict.update, map(__import__, names_list))
        

        【讨论】:

          【解决方案5】:

          我没有找到好的方法,所以我从http://www.djangosnippets.org/snippets/600/采取了一种更简单但丑陋的方法

          try:
              import socket
              hostname = socket.gethostname().replace('.','_')
              exec "from host_settings.%s import *" % hostname
          except ImportError, e:
              raise e
          

          【讨论】:

          • 我可以看到这段代码来自哪里,但是对 exec 的调用让我不寒而栗。我真的不知道在这种情况下这是否有什么大不了的,但我已经学会相信自己对这类事情的直觉。
          • 这在函数内部是非法的,看起来确实很糟糕。
          猜你喜欢
          • 1970-01-01
          • 2017-11-09
          • 1970-01-01
          • 2021-11-11
          • 1970-01-01
          • 1970-01-01
          • 2012-03-23
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多