Python 导入文件夹中所有文件中的所有类(或函数),就好像它们都在 __init__ 文件中一样

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16788380/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 23:41:16  来源:igfitidea点击:

Import all classes (or functions) in all files in folder, as if they were all in the __init__ file

pythonpython-import

提问by olofom

I have a folder with multiple files containing a lot of different classes. These could all be in one big file but for the sake of making it a bit easier to read I've split it up in multiple files depending on what the classes belongs to.

我有一个包含多个文件的文件夹,其中包含许多不同的类。这些都可以放在一个大文件中,但为了更容易阅读,我根据类所属的内容将其拆分为多个文件。

I'd like to import all classes from all files in the folder into the __init__file so that I can import anything from the folder without knowing in what file it belongs to.

我想将文件夹中所有文件中的所有类导入到__init__文件中,以便我可以从文件夹中导入任何内容,而无需知道它属于哪个文件。

Example:

例子:

/kitchen
 + __init__.py
 + fridge.py
 + stove.py
 + cupboard.py

Now I have to do

现在我必须做

from kitchen.fridge import milk

When I'd like to do

当我想做的时候

from kitchen import milk

The equivalent of this I can get through in __init__.pydo:

我可以通过__init__.py这样做的等价物:

from kitchen.fridge import *
from kitchen.stove import *
from kitchen.cupboard import *

And then I can do

然后我可以做

from kitchen import milk

But I'd like it to take all files in the folder without having to specify it explicitly (so that files can be dumped there and then used).

但我希望它能够获取文件夹中的所有文件,而无需明确指定它(以便文件可以在那里转储然后使用)。

Is there any way of doing this?

有没有办法做到这一点?

采纳答案by abarnert

This is a very bad idea. If you want to add a mechanism for files to be "dumped there and used", you probably want to come up with a plugin scheme, and explicitly search the plugin directory(ies).

这是一个非常糟糕的主意。如果你想添加一种机制让文件“转储到那里并使用”,你可能想提出一个插件方案,并明确搜索插件目录。

The way you normally do this is to iterate one or more plugin directories with os.listdiror os.walk, then, for each Python file, use importlib(or lower-level equivalents from imp, in Python 2.x) to import it by path.

您通常执行此操作的方法是使用os.listdir或迭代一个或多个插件目录os.walk,然后,对于每个 Python 文件,使用importlib(或来自impPython 2.x 中的低级等效项)按路径导入它。

However, if you really insist on faking things this way inside a package, you can do basically the same tricks within the __init__.pyfile, using os.path.dirname(__file__)as the plugin directory.

但是,如果您真的坚持在包中以这种方式伪造内容,则可以在__init__.py文件中使用基本相同的技巧,将其os.path.dirname(__file__)用作插件目录。

And, if you really insist on doing the equivalent of from foo import *instead of import fooby path, that's just as easy—or, alternatively, you can use execfile.

而且,如果你真的坚持做等效的from foo import *而不是import foo通过路径,那同样简单——或者,你可以使用execfile.

If you don't know how to do these simple things, or how to look them up in the docs…?then you definitely shouldn't be attempting this. So, I won't provide sample code in this case.

如果你不知道如何做这些简单的事情,或者如何在文档中查找它们......那么你绝对不应该尝试这个。因此,在这种情况下,我不会提供示例代码。

回答by Lennart Regebro

No, there is not. And in addition to that, you shouldn't import *, but in the __init__.pyimport explicitly. This way of splitting up modules is common and good practice, by the way.

不,那里没有。除此之外,您不应该import *,而是__init__.py明确地在导入中。顺便说一下,这种拆分模块的方式很常见,也是很好的做法。

import *is acceptable if you also define an __all__attribute in each module, but there is no real benefit of doing so, and it tends to break code analyzers.

import *如果您还在__all__每个模块中定义一个属性是可以接受的,但这样做并没有真正的好处,而且它往往会破坏代码分析器。

回答by Mike Müller

Explicit is better than implicit. Don't do this. You can certainly hack something together that does automatic imports to some degree. But it is really not worth it. It is just one extra line per added file in the __init__.pyand you are done. Simple solutions are better, unless you get a lot out of the more complicated one, which certainly is not the case here.

显式优于隐式。不要这样做。您当然可以将某些东西组合在一起,从而在某种程度上进行自动导入。但这真的不值得。中每个添加的文件只需要多出一行__init__.py就完成了。简单的解决方案更好,除非你从更复杂的解决方案中得到很多,但这里肯定不是这种情况。

回答by Daniil Mashkin

import os, sys

dir_path = os.path.dirname(os.path.abspath(__file__))
files_in_dir = [f[:-3] for f in os.listdir(dir_path)
                if f.endswith('.py') and f != '__init__.py']
for f in files_in_dir:
    mod = __import__('.'.join([__name__, f]), fromlist=[f])
    to_import = [getattr(mod, x) for x in dir(mod)]
               # if isinstance(getattr(mod, x), type)]  # if you need classes only

    for i in to_import:
        try:
            setattr(sys.modules[__name__], i.__name__, i)
        except AttributeError:
            pass