简体   繁体   English

Python:如何动态地从模块导入所有方法和属性

[英]Python: How to import all methods and attributes from a module dynamically

I'd like to load a module dynamically, given its string name (from an environment variable). 我想动态加载一个模块,给出它的字符串名称(来自环境变量)。 I'm using Python 2.7. 我正在使用Python 2.7。 I know I can do something like: 我知道我可以这样做:

import os, importlib
my_module = importlib.import_module(os.environ.get('SETTINGS_MODULE'))

This is roughly equivalent to 这大致相当于

import my_settings

(where SETTINGS_MODULE = 'my_settings' ). (其中SETTINGS_MODULE = 'my_settings' )。 The problem is, I need something equivalent to 问题是,我需要相当于的东西

from my_settings import *

since I'd like to be able to access all methods and variables in the module. 因为我希望能够访问模块中的所有方法和变量。 I've tried 我试过了

import os, importlib
my_module = importlib.import_module(os.environ.get('SETTINGS_MODULE'))
from my_module import *

but I get a bunch of errors doing that. 但我得到了一堆错误。 Is there a way to import all methods and attributes of a module dynamically in Python 2.7? 有没有办法在Python 2.7中动态导入模块的所有方法和属性?

If you have your module object, you can mimic the logic import * uses as follows: 如果您有模块对象,则可以模仿逻辑import *使用,如下所示:

module_dict = my_module.__dict__
try:
    to_import = my_module.__all__
except AttributeError:
    to_import = [name for name in module_dict if not name.startswith('_')]
globals().update({name: module_dict[name] for name in to_import})

However, this is almost certainly a really bad idea. 然而,这几乎肯定是一个非常糟糕的主意。 You will unceremoniously stomp on any existing variables with the same names. 你将毫不客气地踩踏任何具有相同名称的现有变量。 This is bad enough when you do from blah import * normally, but when you do it dynamically there is even more uncertainty about what names might collide. 当你通常from blah import *时,这已经足够糟糕,但是当你动态地执行它时,关于名称可能会发生碰撞的更多不确定性。 You are better off just importing my_module and then accessing what you need from it using regular attribute access (eg, my_module.someAttr ), or getattr if you need to access its attributes dynamically. 您最好只导入my_module ,然后使用常规属性访问(例如, my_module.someAttr )访问您需要的内容,或者如果您需要动态访问其属性,则访问getattr

My case was a bit different - wanted to dynamically import the constants.py names in each gameX.__init__.py module (see below), cause statically importing those would leave them in sys.modules forever (see: this excerpt from Beazley I picked from this related question ). 我的情况有点不同 - 想在每个gameX.__init__.py模块中动态导入constants.py名称(见下文),导致静态导入它们将永远留在sys.modules中(参见:我从Beazley中摘录的这个摘录)这个相关的问题 )。

Here is my folder structure: 这是我的文件夹结构:

game/
 __init__.py
 game1/
   __init__.py
   constants.py
   ...
 game2/
   __init__.py
   constants.py
   ...

Each gameX.__init__.py exports an init() method - so I had initially a from .constants import * in all those gameX.__init__.py which I tried to move inside the init() method. 每个gameX.__init__.py导出一个init()方法 - 所以我最初在所有那些gameX.__init__.py from .constants import *from .constants import * ,我尝试在init()方法中移动。

My first attempt in the lines of: 我的第一次尝试:

@@ -275,2 +274,6 @@ def init():
     # called instead of 'reload'
+    yak = {}
+    yak.update(locals())
+    from .constants import * # fails here
+    yak = {x: y for x,y in locals() if x not in yak}
+    globals().update(yak)
     brec.ModReader.recHeader = RecordHeader

Failed with the rather cryptic: 与相当神秘的失败:

SyntaxError: import * is not allowed in function 'init' because it contains a nested function with free variables 语法错误:函数'init'中不允许使用import *,因为它包含带有自由变量的嵌套函数

I can assure you there are no nested functions in there. 我可以向你保证,那里没有嵌套函数。 Anyway I hacked and slashed and ended up with: 无论如何,我砍掉并砍掉了最后:

def init():
    # ...
    from .. import dynamic_import_hack
    dynamic_import_hack(__name__)

Where in game.__init__.py : game.__init__.py

def dynamic_import_hack(package_name):
    print __name__ # game.init
    print package_name # game.gameX.init
    import importlib
    constants = importlib.import_module('.constants', package=package_name)
    import sys
    for k in dir(constants):
        if k.startswith('_'): continue
        setattr(sys.modules[package_name], k, getattr(constants, k))

(for setattr see How can I add attributes to a module at run time? while for getattr How can I import a python module function dynamically? - I prefer to use those than directly access the __dict__ ) (对于setattr,请参阅如何在运行时向模块添加属性?对于getattr 如何动态导入python模块函数? - 我更喜欢使用那些而不是直接访问__dict__

This works and it's more general than the approach in the accepted answer cause it allows you to have the hack in one place and use it from whatever module. 这是有效的,它比接受答案中的方法更通用,因为它允许你在一个地方进行黑客攻击并从任何模块中使用它。 However I am not really sure it's the best way to implement it - was going to ask a question but as it would be a duplicate of this one I am posting it as an answer and hope to get some feedback. 但是我并不确定这是实现它的最佳方式 - 我会问一个问题,但因为这将是一个问题的副本,我将其作为答案发布,并希望得到一些反馈。 My questions would be: 我的问题是:

  • why this "SyntaxError: import * is not allowed in function 'init'" while there are no nested functions ? 为什么这个“SyntaxError:import *在函数'init'中是不允许的”,而没有嵌套函数?
  • dir has a lot of warnings in its doc - in particular it attempts to produce the most relevant, rather than complete, information - this complete worries me a bit dir在其文档中有很多警告 - 特别是它试图产生最相关但非完整的信息 - 这完全让我担心
  • is there no builtin way to do an import * ? 没有内置的方法来进行import * even in python 3 ? 即使在python 3?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM