【问题标题】:Should I always use the most pythonic way to import modules?我应该总是使用最 Pythonic 的方式来导入模块吗?
【发布时间】:2018-04-09 10:18:50
【问题描述】:

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

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'?

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

【问题讨论】:

  • 不要发起一场激烈的战争,但 php 确实鼓励坏习惯。选择第二个。
  • 作为链接问题中已接受答案的作者,我只能支持 klutt 的评论和 Nils Werner 的(优秀)答案:Python 是一种完全不同的语言,具有完全不同的执行模型和完全不同的哲学所以忘记 PHP 并学会用 Python 的方式写东西。
  • 谢谢。你说得对,我喜欢 Nils 的说法。

标签: python frameworks pygame desktop autoloader


【解决方案1】:

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

  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()类,它实现了某个接口来提供spritesmaps等。原因是:Sprites和Maps通常保存在单独的文件中:你绝对不这样做想要做的是查看scenarios__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

【讨论】:

  • 我希望我能两次支持这个答案 - 除了最后一个建议,恕我直言,在这种情况下没有意义
猜你喜欢
  • 2011-09-16
  • 2019-03-14
  • 2022-08-20
  • 1970-01-01
  • 2012-01-10
  • 2011-01-24
  • 1970-01-01
  • 2018-12-06
  • 1970-01-01
相关资源
最近更新 更多