python - 我应该始终使用最 pythonic 的方式来导入模块吗?

标签 python frameworks pygame desktop autoloader

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

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

然后游戏会将“场景”附加到 sys.path 并使用 __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'?

注意:这不是网络应用程序

最佳答案

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

  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()类,它实现了某个接口(interface)来提供spritesmaps等。原因是: Sprite 和 map 通常保存在单独的文件中:你绝对不想做的是查看场景__file__属性并开始猜测它的文件。而是实现一个为其提供统一接口(interface)的方法。

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

关于python - 我应该始终使用最 pythonic 的方式来导入模块吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49730635/

相关文章:

python - 设置 Keras 模型可训练与使每一层可训练之间有什么区别

python - 计算 Pandas 系列 float 中的出现次数

android - 如何为 android google map 创建自动化测试?

frameworks - Phoenix开发的IDE

python - 即使函数设置参数不移动,PygameSprites也会移出屏幕

pygame - 计时器未正确启动并且在 pygame 中重新启动游戏时未重置

python - 如何将 scipy 行矩阵转换为 numpy 数组

python - 如何通过 selenium p 隐藏 chromedriver 登录控制台

java - 为什么有这么多Java框架?

python - 使用 Surface.copy() 有时会失去透明度