在没有前缀

时间:2016-08-25 16:17:19

标签: python python-2.7 module

我正在使用python 2.7。我有一个文件夹,里面有许多.py文件,用于定义我想在主脚本中使用的函数,加载对象等。我想完成以下两个目标:

  1. 从此目录中的所有.py文件加载所有对象,而不事先知道文件名。
  2. 在我的主脚本中访问这些对象而不带前缀,例如无需使用filename.function_name()
  3. 据我所知,这不符合python模块的公认最佳实践。尽管如此:

    • 我正在编写纯粹供我自己使用的代码。它永远不会与他人共享或使用。

    • 在我的开发工作过程中,我经常更改文件的名称,将对象定义从一个文件移动到另一个文件等等。因此,需要转到我的主脚本并更改名称是很麻烦的。每次执行此操作时,函数名前缀都是。

    • 我是一名成年人。我理解名称冲突带来的风险概念。我使用自己的命名约定来创建我创建的函数和对象,以确保它们不会与其他名称冲突。

    我的第一个注意事项是使用os.listdir()循环浏览目录中的文件,然后在这些文件上调用execfile()。如果这不起作用,我在这里查看了回复:Loading all modules in a folder in Python。我找到了许多有用的东西,但没有一个能让我到达我想要的地方。具体来说,如果我的__init__.py文件中包含回复here

    from os.path import dirname, basename, isfile
    import glob
    modules = glob.glob(dirname(__file__)+"/*.py")
    __all__ = [ basename(f)[:-3] for f in modules if isfile(f)]
    

    然后在我的主脚本中使用:

    os.chdir("/path/to/dir/") # folder that contains `Module_Dir`
    from Module_Dir import *
    

    然后我可以访问我目录中文件中定义的所有对象,而无需提前知道这些文件的名称(从而满足我的目标中的#1)。但是,这仍然需要我使用filename.function_name()等来调用这些函数和对象。同样,如果我明确地包含在我的__init__.py文件中:

    from filename1 import *
    from filename2 import *
    etc.
    

    然后我可以在我的主脚本中使用与上面相同的from Module_Dir import *。现在,我可以访问没有前缀的对象,但它要求我明确指定__init__.py中文件的名称。

    是否有可以将这两者结合起来的解决方案,从而实现了我的两个目标?我也尝试过(例如建议here,包括__init__.py中的以下内容:

    import os
    for module in os.listdir(os.path.dirname(__file__)):
        if module == '__init__.py' or module[-3:] != '.py':
            continue
        __import__(module[:-3], locals(), globals())
    del module
    

    但同样,这仍需要名称前缀。我试图看看是否有可选的参数或修改我在这里使用__import__,或使用python 2.7的importlib的应用程序,但是在前面都没有取得进展。

3 个答案:

答案 0 :(得分:0)

好的,这是我根据@meetaig的建议提出的解决方案。我很高兴接受并提出任何其他想法或建议实施这种情况:

import os

def Load_from_Script_Dir(DirPath):
    os.chdir(os.path.dirname(os.path.dirname(DirPath))) ## so that the from .. import syntax later properly finds the directory.
    with open(DirPath + "__init__.py", 'w') as f:
        Scripts = [FileName for FileName in os.listdir(DirPath) if FileName[-3:] == '.py' and '__init__' not in FileName]
        for Script in Scripts: 
            f.write('from %s import *\n'  % Script.replace('.py',''))


# Script_Dir = "/path/to/Script_Dir/"  ## specify location of Script_Dir manually
Script_Dir = os.path.dirname(os.path.abspath(__file__)) + "/Script_Dir/" ## assume Script_Dir is in same path as main.py that is calling this.  Note: won't work when used in REPL.
Load_from_Script_Dir(Script_Dir)
from Script_Dir import *

注意:

  1. 这也要求Script_Dir中的.py文件符合python对象的命名约定,即它们不能以数字开头,不能有空格等。

  2. 此处加载的Script_Dir中的.py文件无法访问主脚本中定义的对象(即使它们是在调用from Script_Dir import *之前定义的)。同样,他们将无法访问Script_Dir中其他脚本中定义的对象。因此,可能仍需要在其他.py文件中使用from filename import objectname等语法。这是不幸的,部分地打败了我希望实现的一些便利,但它至少是对现状的适度改善。

答案 1 :(得分:0)

这是另一种解决方案,基于与我的其他实现相同的一般原则(受到@meetaig在评论中的建议的启发)。然而,这个绕过了使用python模块框架的尝试,而是开发了一种解决方法,以便能够使用execfile()。对我的目的来说似乎更可取,因为:

  1. 如果一个支持脚本定义了使用其他脚本中定义的函数或对象的函数,则无需向其添加额外的from filename import ...集(正如我在其他答案中所述,已失败)很多我希望获得的便利)。相反,就像脚本在一个大文件中一起发生一样,函数/对象只需要在调用给定函数的时间定义。

  2. 同样,支持脚本可以使用主脚本中运行支持脚本之前创建的对象。

  3. 这样可以避免创建一堆.pyc文件,这些文件只会破坏我的目录。

  4. 这同样绕过了(从我的其他解决方案)确保将解释器的工作目录导航到正确位置的需要,以确保主要from ... import ...语句的成功脚本。

  5. import os
    
    Script_List_Name = "Script_List.py"
    
    def Load_from_Script_Dir(DirPath):
        with open(DirPath + Script_List_Name, 'w') as f:
            Scripts = [FileName for FileName in os.listdir(DirPath) if FileName[-3:] == '.py' and FileName != Script_List_Name]
            for Script in Scripts: 
                f.write('execfile("%s")\n'  % (DirPath + Script))
    
    Script_Dir = "/path/to/Script_Dir/"
    
    Load_from_Script_Dir(Script_Dir)
    execfile(Script_Dir + Script_List_Name)
    

    或者,如果没有必要在函数内部进行加载,如果包含在主脚本中,则以下循环也可以正常工作(我最初被抛弃了,因为当我试图构建一个函数来执行这个循环,我认为它只将对象加载到该函数的范围内,因此它们无法在其他地方访问,这种操作不同于其他语言,如Julia,其中相同函数会成功将对象放入函数外的范围内:

    import os
    Script_Dir = "/path/to/Script_Dir/"
    for FileName in os.listdir(Script_Dir):
        if FileName[-3:] == '.py':
            print "Loading %s" %FileName
            execfile(Script_Dir + FileName)
    

答案 2 :(得分:0)

使用路径

"""
Imports all symbols from all modules in the package
"""
from pathlib import Path
from importlib import import_module


for module_path in Path(__file__).parent.glob('*.py'):
    if module_path.is_file() and not module_path.stem.startswith('_'):
        module = import_module(f'.{module_path.stem}', package=__package__)
        symbols = [symbol for symbol in module.__dict__ if not symbol.startswith("_")]
        globals().update({symbol: getattr(module, symbol) for symbol in symbols})