简体   繁体   English

我是否应该始终使用最pythonic的方式导入模块?

[英]Should I always use the most pythonic way to import modules?

I am making a tiny framework for games with pygame, on which I wish to implement basic code to quickly start new projects. 我正在为pygame开发一个小型游戏框架,在该框架上我希望实现基本代码以快速启动新项目。 This will be a module that whoever uses should just create a folder with subfolders for sprite classes, maps, levels, etc. My question is, how should my framework module load these client modules? 这将是一个模块,无论谁使用,都应仅创建一个带有子文件夹的子文件夹,用于存放精灵类,地图,关卡等。我的问题是,我的框架模块应如何加载这些客户端模块? I was considering to design it so the developer could just pass to the main object the names of the directories, like: 我正在考虑对其进行设计,以便开发人员可以将目录名称传递给主对象,例如:

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

Then game will append 'scenarios' to sys.path and use __import__() . 然后游戏会将“场景”追加到sys.path并使用__import__() I've tested and it works . 我已经测试了而且可以用 But then I researched a little more to see if there were already some autoloader in python, so I could avoid to rewrite it, and I found this question Python modules autoloader? 但是后来我研究了一下,看是否在python中已经有一些自动加载器,所以我可以避免重写它,而我发现了这个问题Python模块自动加载器? Basically, it is not recommended to use a autoloader in python, since "explicit is better than implicit" and "Readability counts". 基本上,不建议在python中使用自动加载器,因为“显式优于隐式”和“可读性”。

That way, I think, I should compel the user of my module to manually import each of his/her modules, and pass these to the game instance, like: 这样,我认为,我应该强迫我的模块的用户手动导入他/她的每个模块,并将它们传递给游戏实例,例如:

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

But this doesn't looks good to me, not so confortable. 但这对我来说并不好,不那么舒服。 See, I am used to work with php, and I love the way it works with it's autoloader. 看,我曾经使用过php,我喜欢它与自动加载器一起工作的方式。 So, the first exemple has some problability to crash or be some trouble, or is it just not 'pythonic'? 因此,第一个示例可能会崩溃或出现麻烦,还是不是“ pythonic”?

note: this is NOT an web application 注意: 这不是Web应用程序

I wouldn't consider letting a library import things from my current path or module good style. 我不会考虑让库从我当前的路径或模块好的样式中导入内容。 Instead I would only expect a library to import from two places: 相反,我只希望库从两个地方导入:

  1. Absolute imports from the global modules space, like things you have installed using pip . 从全局模块空间绝对导入,就像您使用pip安装的东西一样。 If a library does this, this library must also be found in its install_requires=[] list 如果库执行此操作,则还必须在其install_requires=[]列表中找到该库。

  2. Relative imports from inside itself. 从自身内部的相对进口。 Nowadays these are explicitly imported from . 如今,这些已明确从中导入. :

     from . import bla from .bla import blubb 

This means that passing an object or module local to my current scope must always happen explicitly: 这意味着必须始终显式地传递本地对象到我当前作用域的模块:

from . import scenarios
import framework

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

This allows you to do things like mock the scenarios module: 这使您可以进行模拟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)

Also you can implement a framework.utils.Scenario() class that implements a certain interface to provide sprites , maps etc. The reason being: Sprites and Maps are usually saved in separate files: What you absolutely do not want to do is look at the scenarios 's __file__ attribute and start guessing around in its files. 您还可以实现一个framework.utils.Scenario()类,该类实现某个接口以提供spritesmaps等。原因是:Sprites和Maps通常存储在单独的文件中: 您绝对不想做的是查看scenarios__file__属性,并开始在其文件中进行猜测。 Instead implement a method that provides a unified interface to that. 而是实现提供一个统一接口的方法。

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
        ...

And your user-specific scenarios will derive from it and optionally overload the loading methods 您的特定于用户的方案将从中得出,并有选择地重载加载方法

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
        ...

What you can also do is have framework ship its own framework.contrib.scenarios module that is used in case no scenarios= keyword arg was used (ie for a square default map and some colorful default textures) 您还可以做的是让framework附带自己的framework.contrib.scenarios模块,该模块在不使用scenarios=关键字arg的情况scenarios=使用(例如,用于方形默认贴图和一些彩色默认纹理)

from . import contrib

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM