代码之家  ›  专栏  ›  技术社区  ›  Albert Uler Silva Melo

我是否应该始终使用最具python风格的方式导入模块?

  •  1
  • Albert Uler Silva Melo  · 技术社区  · 6 年前

    我正在用pygame为游戏制作一个小框架,我希望在这个框架上实现基本代码以快速启动新项目。这将是一个模块,无论谁使用它,都应该创建一个包含精灵类、贴图、级别等子文件夹的文件夹。 我的问题是,我的框架模块应该如何加载这些客户端模块?我正在考虑设计它,以便开发人员可以将目录的名称传递给主对象,例如:

    game = Game()
    game.scenarios = 'scenarios'
    

    然后游戏会将“场景”附加到系统中。路径和使用 __import__() 我已经测试过了,效果不错 。 但后来我进一步研究了一下,看看python中是否已经有一些自动加载器,这样我就可以避免重写它,我发现了这个问题 Python modules autoloader? 基本上,不建议在python中使用自动加载器,因为“显式优于隐式”和“可读性计数”。

    这样,我认为,我应该强制我的模块的用户手动导入他/她的每个模块,并将其传递给游戏实例,如:

    import framework.Game
    import scenarios
    #many other imports
    game = Game()
    game.scenarios = scenarios
    #so many other game.whatever = whatever
    

    但我觉得这不太好,不太舒服。看,我习惯于使用php,我喜欢它与自动加载器的配合方式。 因此,第一个例子可能会崩溃或遇到一些麻烦,或者它只是不“pythonic”?

    注: 这不是web应用程序

    1 回复  |  直到 6 年前
        1
  •  4
  •   Nils Werner    6 年前

    我不会考虑让一个库从我当前的路径或模块中导入好的样式。相反,我只希望库从两个地方导入:

    1. 从全局模块空间进行绝对导入,就像您使用 pip 。如果库执行此操作,则还必须在其 install_requires=[] 列表

    2. 从内部的相对导入。如今,这些都是从 . :

      from . import bla
      from .bla import blubb
      

    这意味着必须始终显式地将本地对象或模块传递到当前作用域:

    from . import scenarios
    import framework
    
    scenarios.sprites  # attribute exists
    game = framework.Game(scenarios=scenarios)
    

    这允许您进行模拟 scenarios 模块:

    import types
    import framework
    
    # a SimpleNamespace looks like a module, as they both have attributes
    scenarios = types.SimpleNamespace(sprites='a', textures='b')
    scenarios.sprites  # attribute exists
    game = framework.Game(scenarios=scenarios)
    

    还可以实现 framework.utils.Scenario() 实现某个接口以提供 sprites ,则, maps 等等。原因是:精灵和贴图通常保存在单独的文件中: 你绝对不想做的事 就是看看 场景 __file__ 属性,并开始在其文件中进行猜测。相反,实现一个方法,该方法提供了一个统一的接口。

    class Scenario():
        def __init__(self):
            ...
    
        def sprites(self):
            # optionally load files from some default location
            # If no such things as a default location exists, throw a NotImplemented error
            ...
    

    您的特定于用户的场景将从中派生出来,并可以选择重载加载方法

    import framework.utils
    class Scenario(framework.utils.Scenario):
        def __init__(self):
            ...
    
        def sprites(self):
            # this method *must* load files from location
            # accessing __file__ is OK here
            ...
    

    你能做的就是 framework 自己发货 framework.contrib.scenarios 案例编号中使用的模块 scenarios= 使用了关键字arg(即,对于方形默认贴图和一些彩色默认纹理)

    from . import contrib
    
    class Game()
        def __init__(self, ..., scenarios=None, ...):
            if scenarios is None:
                scenarios = contrib.scenarios
            self.scenarios = scenarios