使用“import __main__”是个好习惯吗?

2023-12-07

我正在开发一个相对较大的 Python 应用程序,并且我希望将一些资源保留为可在多个不同模块中访问的全局变量。这些值包括版本号、版本日期、全局配置和一些资源的静态路径。我还包括了一个DEBUG由命令行选项设置的标志,以便我可以在调试模式下运行我的应用程序,而不需要完整的环境。

我一直小心地确保我导入的值在程序运行过程中不会改变,并且我已将它们记录为不应触及的全局常量变量。我的代码基本上看起来像


# Main.py
import wx
from gui import Gui

DEBUG = False
GLOBAL_CONFIG = None
VERSION = '1.0'
ICON_PATH = 'some/path/to/the/app.ico'

def main():
    global DEBUG, GLOBAL_CONFIG

    # Simplified
    import sys
    DEBUG = '--debug' in sys.argv

    GLOBAL_CONFIG = load_global_config()
    # Other set-up for the application, e.g. setting up logging, configs, etc

    app = wx.App()
    gui = Gui()
    app.MainLoop()

if __name__ == '__main__':
    main()

# gui.py
import wx
from __main__ import DEBUG, GLOBAL_CONFIG, ICON_PATH

import controller


class Gui(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None)

        icon = wx.Icon(ICON_PATH, wx.BITMAP_TYPE_ICO)
        self.SetIcon(icon)

        # Always make a copy so we don't accidentally modify it
        conf = GLOBAL_CONFIG.copy()
        self.controller = controller.Controller(conf)

        # More setup, building the layout, etc

# controller.py
from __main__ import DEBUG

import logging
log = logging.getLogger('controller')

class Controller(object):
    def __init__(self, conf):
        if DEBUG:
            log.info("Initializing controller in DEBUG mode")
        self.conf = conf
        # Other setup ...

这显然与我的应用程序的实际情况相去甚远,并且忽略了错误处理、文档和基本上所有的实现细节。

现在,我已经看到它说这是一个坏主意,但没有解释原因。由于在谷歌搜索“python import __main__”的变体时,大多数结果都是关于什么的问题if __name__ == '__main__'是的,很难找到关于这个主题的一些可靠信息。到目前为止,我没有遇到任何问题,而且实际上非常方便。

那么这是否被认为是良好的 Python 实践,或者我是否有理由避免这种设计?


我认为有两个主要(哈哈)原因可以避免这种模式。

  • 它混淆了您正在导入的变量的来源。
  • 如果你的程序有多个入口点,它就会崩溃(或者至少很难维护)。想象一下,如果有人(很可能是您)想要将您的功能的某些子集提取到一个独立的库中 - 他们必须删除或重新定义这些孤立引用中的每一个,以使该东西在您的应用程序之外可用。

如果您完全控制应用程序,并且您的功能永远不会有另一个入口点或其他用途,并且您确定您不介意这种歧义,那么我认为没有任何客观的原因为何from __main__ import foo图案不好。我个人不喜欢它,但同样,基本上是出于上述两个原因。


我认为更强大/开发人员友好的解决方案可能是这样的,创建一个专门用于保存这些超级全局变量的特殊模块。然后您可以导入该模块并参考module.VAR任何您需要设置的时候。本质上,只是创建一个特殊的模块命名空间来存储超全局运行时配置。

# conf.py (for example)
# This module holds all the "super-global" stuff.
def init(args):
    global DEBUG
    DEBUG = '--debug' in args
    # set up other global vars here.

然后你会像这样使用它:

# main.py
import conf
import app

if __name__ == '__main__':
    import sys
    conf.init(sys.argv[1:])

    app.run()

# app.py
import conf

def run():
    if conf.DEBUG:
        print('debug is on')

注意使用conf.DEBUG而不是from conf import DEBUG。这种结构意味着您can在程序的生命周期中更改变量,并将该更改反映在其他地方(显然,假设是单个线程/进程)。


另一个好处是这是一种相当常见的模式,因此其他开发人员很容易识别它。它很容易与settings.py各种流行应用程序使用的文件(例如django),尽管我避免使用这个特定的名字,因为settings.py通常是一堆静态对象,而不是运行时参数的命名空间。上述配置命名空间模块的其他好名称可能是runtime or params, 例如。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用“import __main__”是个好习惯吗? 的相关文章

随机推荐

  • 扩展多边形的范围 - Google Maps V3 Javascript API

    我的目标是检测标记是否位于形状奇怪的多边形对象内 想想 25 个不同的点 我注意到 LatLngBounds 属性仅包含两组 LatLng 即使在使用 extend 函数之后也是如此 例如 34 347971491244955 122 40
  • const 引用的默认参数中使用的统一初始值设定项

    这是合法的 c 0x 语法吗 class A public void some function const std set
  • Java 中使用同步块的并发未给出预期结果

    下面是一个简单的 java 程序 它有一个名为 cnt 的计数器 该计数器会递增 然后添加到名为 monitor 的列表中 cnt 由多个线程递增 值由多个线程添加到 monitor 在方法 go 的末尾 cnt 和 monitor siz
  • 如何打开包含图像数组的 fancybox

    我在 JS 中有一组图像 ulrs photos img1 jpg img2 jpg 我正在使用 Fancybox 2 如何打开包含数组图像的 fancybox start slides fancybox openEffect elasti
  • 你能用 JavaScript 编写嵌套函数吗?

    我想知道 JavaScript 是否支持在另一个函数中编写函数或嵌套函数 我在博客中读到 这真的可能吗 事实上 我已经使用过这些 但不确定这个概念 我对此真的不清楚 请帮忙 这真的可能吗 Yes function a x lt functi
  • 如何获取javax.comm API?

    我最近下载了一个项目SMS正在发送 但是当我尝试编译代码时 它给出了在线错误import javax comm 谁能告诉我在哪里可以找到javax comm以及放置在哪里 这样就不会出现编译错误 Oracle Java 通信 API 参考
  • 从一个枚举状态移动到下一个状态并循环

    我只有具有 3 种模式 ledOn ledBlink ledOFF 的枚举器 并且有一个可变模式来跟踪特定对象的模式 例如 我有一个 LED 以 ledOn 模式启动 我想在 5 秒后移动到下一个元素 即 ledBlink 然后移动到 le
  • Django self.cleaned_data Keyerror

    我正在编写一个 Django 网站 并且正在编写自己的表单验证 class CreateJobOpportunityForm forms Form subject forms CharField max length 30 start da
  • UIButton 中图像下的标签

    我正在尝试创建一个按钮 该按钮在图标下方有一些文本 有点像应用程序按钮 但它似乎很难实现 任何想法如何让文本显示below图像与UIButton 或者您可以只使用此类别 ObjC interface UIButton VerticalLay
  • 如何解决“react-native start”错误

    我刚刚安装了 node js 和 cli 安装了node js 安装了react native cli npm g react native cli 并创建了一个 新项目 react native init new project 在 ne
  • 使用 jQuery 将三个重复的 div 组合并为一个

    我这里还有另一个问题 我有几个重复的 div 组 一组有3个不同班级的分区 我需要做的是将其包装到一个 容器 中 当我使用wrapAll时 它会将所有内容包装到一个div中 这是我的 html div class bb box tl div
  • 使用jquery ajax将javascript对象转为php

    我有一个数组或一个 javascript 对象 我创建如下 arr arr length obj其中 obj 是一个经典的 JSON 字符串 例如 id 1 So arr似乎是一个 JavaScript 对象数组 我可以这样访问它 arr
  • 无法使用自定义适配器理解 NullPointerException

    我正在尝试创建一个列表视图 它作为可以显示 html 内容的 TextView WebView 和其他基本 TextView 我尝试扩展 SimpleAdapter 但我遇到了这个问题 如果有人能指出我正在做的错误 我会很高兴 在onCre
  • 从BackgroundWorker内的剪贴板获取数据

    我有一个后台工作者 在 DoWork 方法中我有以下内容 var clipboardData Application Current Dispatcher Invoke new Action gt Clipboard GetData Dat
  • 如何将操作栏选项卡向右对齐?

    我以编程方式添加了操作栏选项卡 我不知道如何将操作栏选项卡向右对齐 ActionBar bar getActionBar bar setNavigationMode ActionBar NAVIGATION MODE TABS instan
  • Google Apps 脚本中的 Cookie 处理 - 如何在标头中发送 Cookie?

    我正在尝试编写一个简单的脚本 从网页中获取文本并处理该字符串 但是 该网站要求我登录 我成功登录该网站 这是我登录的方式 var payload name1 val1 name2 val2 var opt payload payload m
  • 如何格式化 Winform 中 LostFocus 事件的所有文本框值

    我需要在失去焦点事件时向任何相关文本框值中每个数值的千位添加逗号 我创建了以下函数 public static void FormatNumerical this Control control if control is TextBox
  • 递归函数的复杂性 - 时间和空间

    我有兴趣知道如何计算递归函数的时间和空间复杂度 如排列 斐波那契 描述here 一般来说 我们可以在很多地方进行递归 而不仅仅是排列或递归 所以我正在寻找通常遵循的方法来计算时间和空间复杂度 谢谢 看一眼http www cs duke e
  • 带有 if 语句的函数中的全局变量

    好吧 我目前正在做一个用 python 制作二十一点游戏的项目 但遇到了一些麻烦 我的问题之一是我不知道何时将变量定义为全局变量 特别是在带有 if 语句的函数中 如果我在 if 语句之外有一个全局变量 我是否必须声明该变量在 if 语句内
  • 使用“import __main__”是个好习惯吗?

    我正在开发一个相对较大的 Python 应用程序 并且我希望将一些资源保留为可在多个不同模块中访问的全局变量 这些值包括版本号 版本日期 全局配置和一些资源的静态路径 我还包括了一个DEBUG由命令行选项设置的标志 以便我可以在调试模式下运