2 回答
TA贡献1798条经验 获得超7个赞
这样的问题可能存在争议。但我通常会说是的,这是“不好的做法”,因为变革的范围和影响确实变得模糊。请注意,您描述的用例实际上不是关于共享配置,而是关于程序函数、对象、模块交换数据的不同部分,因此它是(元)变量的一些变体global。
读取通用配置值可能没问题,但一路更改它们...您可能会忘记在导入模块/修改值时发生的情况以及顺序。例如假设config.py和 两个模块m1.py:
import config
print(config.x)
config.x=1
和m2.py:
import config
print(config.x)
config.x=2
和 amain.py就这样做:
import m1
import m2
import config
print(config.x)
或者:
import m2
import m1
import config
print(config.x)
您在每个模块以及其他任何模块(包括main.py此处)中找到配置的状态取决于导入发生的顺序以及谁在何时分配什么值。即使对于完全在您控制之下的程序,这也可能很快变得令人困惑(以及错误的根源)。
对于运行时数据以及在对象和模块之间传递信息(您的示例确实是这样,而不是在模块之间预定义和共享的配置),我建议您考虑在自定义状态(配置)对象中描述信息并将其传递通过适当的接口。但实际上可能只需要一个函数/方法参数即可。确切的形式取决于您到底想要实现什么以及您的整体设计是什么。
在您的示例中,other.py之前调用或导入时的行为有所不同top.py,在最小的示例中可能仍然看起来很明显且易于管理,但实际上并不是一个非常合理的设计。任何阅读代码的人(包括未来的你)都应该能够遵循其逻辑,而这个 IMO 打破了它的流程。
对于您所描述的内容,最简单(也是程序性的)示例,现在我希望能够更好地理解,那就是重新other.py创建您当前的行为:
def do_stuff(value):
print(value) # We did something useful here
if __name__ == "__main__":
do_stuff(None) # Could also use config with defaults
您top.py可能是入口点并协调导入和执行:
import other
x = get_the_value()
other.do_stuff(x)
您当然可以引入一个接口来配置do_stuff一个dict或一个自定义类,即使使用默认实现config.py:
class Params:
def __init__(self, x=None):
self.x = x
和你的other.py:
def do_stuff(params=config.Params()):
print(params.x) # We did something useful here
在你的上top.py你可以使用:
params = config.Params(get_the_value())
other.do_stuff(params)
但您也可以拥有任何特定于用例的值源:
class TopParams:
def __init__(self, url):
self.x = get_value_from_url(url)
params = TopParams("https://example.com/value-source")
other.do_stuff(params)
x甚至可以是property您每次访问它时检索的内容...或者在需要时懒惰地检索然后缓存...同样,这实际上是您需要做什么的问题。
TA贡献1828条经验 获得超6个赞
“从一个模块修改另一个模块的属性是一种不好的做法吗?”
这被认为是不好的做法——违反了德米特法则,这实际上意味着“与朋友交谈,而不是与陌生人交谈”。
对象应该公开行为和功能,但应该隐藏数据。DataStructures 应该公开数据,但不应该有任何方法(公开的)。德米特定律不适用于此类数据结构。OOP 纯粹主义者可能会使用 setter 和 getter 来覆盖此类 DataStructures,但它实际上在 Python 中没有增加任何价值。
我保留配置的首选方法是(此处不使用 attrs):
# conf_xy.py
"""
config is code - so why use damned parsers, textfiles, xml, yaml, toml and all that
if You just can use testable code as config that can deliver the correct types, etc.
as well as hinting in Your favorite IDE ?
Here, for demonstration without using attrs package - usually I use attrs (read the docs)
"""
class ConfXY(object):
def __init__(self) -> None:
self.x: int = 1
self.z: float = get_z_from_input()
...
conf_xy=ConfXY()
# other.py
from conf_xy import conf_xy
...
y = conf_xy.x * 2
...
添加回答
举报