Python``uiu init_uu.py`和cod中对象的初始化

2024-09-28 15:23:06 发布

您现在位置:Python中文网/ 问答频道 /正文

我已经阅读了关于__init__.py文件的文档和一些关于SO的好问题,但是我仍然对它的正确用法感到困惑。在

上下文

我有一个包含许多包和子包的代码。我已经定义了许多类,其中一些类需要为整个用户会话创建一个(而且只有一个)实例。然后,这些新对象将在代码的不同部分中使用,因此每当我(或用户)更新此对象中的数据/信息时,它将在所有代码中使用,而无需更改任何其他内容。 更清楚地说,让我给你看一个我所说的基本方案。在

该规范的结构过于简化,如:

root/
    __init__.py
    tools/
        __init__.py
        ... (some modules)
        aliases.py (which defines the class Aliases)
    physics/
        __init__.py
        ... (some modules)
        constants/
            ... (some modules)
            constants.py (which defines the class Ctes)
        units.py (which defines the class Units)

在代码中,我需要管理别名、单位和常量。我发现处理这个问题的方法是创建每个实例的一个实例,并在所有代码中使用它。用这种方法, 例如,我确信,如果在代码仍在运行时添加了别名,那么它可以在代码中的任何地方使用,因为只有一个别名的共享实例。 这就是我需要的(顺便说一下,单位和常量也是一样的)。在

现状

至于现在,我认为我这样做不是最好的。实际上,我是在声明类之后,在同一个文件中创建的实例,比如别名:

root/tools/aliases.py

^{pr2}$

然后,在任何需要使用别名的文件中,我都会:

any_file.py(代码中的任何位置)

from root.tools.aliases import ALIASES

ALIASES.method1() # possibly in functions or other classes
ALIASES.method2() # ... etc

对于其他一些类,我甚至在代码的根目录使用__init__.py文件:

root/__init__.py

# CTES is the instance of Ctes() created in root/physics/constants/constants.py
from root.physics.constants.constants import CTES
CTES.add(...) # add a new constant that needs to be known

(当然,CTES不仅仅存储一些常量,我还定义了一些方法来利用它们,因此在这个类中包含它们是有意义的,而不是仅仅将它们定义为常规python 模块中的常数)

问题

我在想我是不是做得对(也许不是)。也许最好使用文件__init__.py并在其中启动共享实例。但是这样做是否会带来一些问题(比如依赖循环,或者增加内存使用?另外,如何在代码的其他地方使用创建的实例?这样地?公司名称:

root/tools/__init__.py

import root.tools.aliases as Al
ALIASES = Al.Aliases()
# should I delete the imported module: del Al ??

然后在any_file.py

from root.tools import ALIASES
ALIASES.method(...)

或者,应该将所有这些实例都包含在一个文件中(例如root/shared.py),并将其导入root/__init__.py中,这样我就确定它已经启动了?在

我已经读过很多遍了,最好保持__init__.py文件为空(目前我的代码就是这样,当然除了root/__init__.py)。你怎么认为?在

我有点迷路了(你可能从我不太清楚的事实中可以看出这一点)。欢迎任何帮助/建议。我想避免任何非Python式的解决方案,或可能混淆用户,或使事情变得不安全的解决方案。在


Tags: 文件the实例代码用户pyimport定义
2条回答

在模块中创建一个单独的实例是很好的。使用全局变量没有错(除非它们不合适,但这适用于任何语言特性)。唯一的潜在缺点是如果不使用它而导入该模块并浪费初始化该类的资源。除非您的类在创建时做了一些非常重要的事情(我对此非常怀疑),否则这种影响可以忽略不计。我唯一的建议就是调整你的名字。你的类应该以下划线开头,这样模块的用户就知道不要碰它,你的实例应该是小写的。你使用的方法不会产生任何不良副作用。在

没有人说你必须把所有的类放在它们自己的文件中,或者说你必须使用所有的类。也许一个包含函数的别名模块和模块全局参数中的“private”状态对您更有意义。由于您不使用对象系统来获取具有独立状态的多个实例,所以创建类的唯一原因是如果您喜欢这样组织代码和API。这里最重要的是,您对代码的组织方式和模块的使用方式感到满意。过多地使用面向对象的技术比使用太少的imo更容易混淆用户。在

有很多其他的方法来处理单例。这是我第一次听说“博格模式”,对我来说,这听起来既浪费又愚蠢,但我想至少在技术上是可行的,浪费至少可以忽略不计。您可以编写一个函数,在第一次调用一个类时实例化它,将它存储在一个全局中,并在随后的调用中返回该全局(但是,您必须担心线程化,这并不是您已经在做的问题)。您可以创建一个类,它的__init__方法引发TypeError,这样它就不能被实例化了,并且可以使用classmethods或staticmethods执行所有操作,保持类本身所需的所有状态。甚至可以创建一个每次都返回相同实例的类。所有这些的结果是,从模块中获取一个对象,然后在代码中使用它,之后使用它的方式看起来也一样。在

我认为你应该在你的一个模块中内联实例化你的类,就像你发布的代码一样,因为它是有效的,这是一个通用的模式,是合理的,对你来说是有意义的。在

没有理由删除已导入的模块。你什么也省不了。一旦导入,模块就永远存在(除非您积极地做一些奇怪的事情来消除它),全局变量并不是您需要保存的宝贵资源。在

只要使用相对名称(即别名而不是root.tools.aliases). 循环依赖是一个真正的问题,所以要小心。只要您的模块只导入树中更深层次的内容,并且您认为是“较低级别”(意味着这些较低级别的模块不会导入可能正在使用它们的较高级别的内容),您就应该没事了。我警告不要在__init__.py,中放置任何实质性的代码,但是我认为如果您希望实例存在的话,实例化类是可以的。在

使用Borg pattern在整个代码中实现所有共享类,然后将它们存储在它们自己的模块中(或捆绑在一起),只要合适。在

然后在需要的地方导入它们并实例化类。它们都将共享相同的上下文,甚至可以微调每个实例化实例的行为。在

如果它们被隔离在它们自己的模块中,那么就不会有任何循环依赖关系,并且可以将导入期间解释器的解析时间减至最少。最好的是,您不会因为在别处导入全局变量而污染您的命名空间。当函数超出范围时,实例将被标记为删除,但状态将与类定义一起保留。在

相关问题 更多 >