Python 导入 - 得墨忒耳法则
得墨忒耳定律
Python 导入可能有点棘手。 Demeter 准则及其对 python 导入的应用程序可以帮助您掌握它们,并编写更用户友好、可测试和可靠的代码。
根据维基百科,得墨忒耳定律(或最少知识原则)是一个软件开发指南,可以这样总结:
-
每个单元应该只对其他单元有有限的了解:只有与当前单元“密切”相关的单元。
-
每个单元只应该和它的朋友交谈;不要和陌生人说话。
-
只与您的直系朋友交谈。
如果我们想将这些应用到 python 导入(python 模块将是单元),它会变成这样:
- 每个模块应该只导入子模块的公共对象,但只能从最近的子模块导入。 (又名“直接朋友”)
方法
为了实现这一点,关键是在每个模块中显式声明(尽管是 _init_.py)暴露了哪些对象。然后这些对象可以被父模块文件夹访问,如果需要,也可以重新公开它们。
这种方法的好处是:
-
您的 _init_.py 文件成为某种“文档”,说明哪些对象应该从其他模块访问或不访问。
-
您完全控制您的导入系统,这是松耦合的关键。
-
最终用户(使用您的模块的其他开发人员)体验得到增强,导入简短明了。
缺点是它更冗长。
第一个例子
假设这个设置:
project
│ __main__.py
└───demeter
│ │ __init__.py
│ └───module1
│ │ __init__.py
│ │ code1.py
进入全屏模式 退出全屏模式
# demeter/module1/code1.py
class MyClass1:
pass
进入全屏模式 退出全屏模式
通过该设置,我们可以直接从 _main_.py 访问 MyClass1 类:
# __main__.py
from demeter.module1.code1 import MyClass1
class1 = MyClass1()
进入全屏模式 退出全屏模式
这可行,但是这是违反 demeter 的法律:_main_.py import MyClass1 from demeter/module1/code1.py 这不是“直接朋友”。
检测它的好气味是长期进口的。应用得墨忒耳定律时,导入通常很短。
一种更清洁的方法是......
1.将模块1中的MyClass1显式暴露给上层模块:
# demeter/module1/__init__.py
from demeter.module1 import code1 as code1
MyClass1 = code1.MyClass1
进入全屏模式 退出全屏模式
1.重新暴露给上层:
# demeter/__init__.py
from demeter import module1
MyClass1 = module1.MyClass1
进入全屏模式 退出全屏模式
1.使用它
# __main__.py
from demeter import module1
MyClass1 = module1.MyClass1
进入全屏模式 退出全屏模式
那样:
-
_main_.py 只知道 demeter 模块,而 demeter 模块只知道 module1 模块。尊重最少知识的原则
-
模块(demeter 和 module1)显式暴露了可以从中使用的内容(显式优于隐式,https://www.python.org/dev/peps/pep -0020/)。
第二个例子
假设先前设置的此扩展:
project
│ __main__.py
└───demeter
│ │ __init__.py
│ └───module1
│ │ __init__.py
│ │ code1.py
| └───module2
│ │ __init__.py
│ │ code2.py
进入全屏模式 退出全屏模式
# demeter/module1/module2/code2.py
class MyClass2:
pass
进入全屏模式 退出全屏模式
要在 _main_.py 中使用 MyClass2,我们将...
将其暴露给模块 1:
# demeter/module1/module2/__init__.py
from demeter.module1.module2 import code2 as code2
MyClass2 = code2.MyClass2
进入全屏模式 退出全屏模式
重新暴露它,但这次是从模块 1:
# demeter/module1/__init__.py
from demeter.module1 import code1 as code1
from demeter.module1 import module2 as module2
MyClass1 = code1.MyClass1
MyClass2 = module2.MyClass2
进入全屏模式 退出全屏模式
和...
# demeter/__init__.py
from demeter import module1
MyClass1 = module1.MyClass1
MyClass2 = module1.MyClass2
进入全屏模式 退出全屏模式
最后,从你的 _main_.py 中使用它:
# __main__.py
from demeter import module1
MyClass1 = module1.MyClass1
MyClass2 = module1.MyClass2
进入全屏模式 退出全屏模式
整个模块示例
得墨忒耳定律也可以应用于整个模块。
前面的例子可能是这样的:
# demeter/module1/code1.py
class MyClass1:
pass
进入全屏模式 退出全屏模式
# demeter/module1/module2/code2.py
class MyClass2:
pass
进入全屏模式 退出全屏模式
# demeter/module1/module2/__init__.py
from demeter.module1.module2 import code2 as code2
进入全屏模式 退出全屏模式
# demeter/module1/__init__.py
from demeter.module1 import code1 as code1
from demeter.module1 import module2 as module2
MyClass1 = code1.MyClass1
进入全屏模式 退出全屏模式
# demeter/__init__.py
from demeter import module1
MyClass1 = module1.MyClass1
进入全屏模式 退出全屏模式
# demeter/__main__.py
import demeter
module1 = demeter.module1
MyClass1 = module1.MyClass1
MyClass2 = module1.module2.code2.MyClass2
进入全屏模式 退出全屏模式
第二种方法看起来与不良实践示例非常相似,不是吗?
但是,关键点是每个所需的模块和对象都明确地公开。
因此,您仍然可以完全控制您的模块系统,并且您尊重最少知识的原则。
VSCode,Pylance,Pyrights
如果您使用 VSCode 和 Pylance(在后台使用 Pyrights),此方法将避免您出现一些reportUnknownMemberType 错误
[](https://res.cloudinary.com/practicaldev/image/fetch/s--Vl0rufon--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to- uploads.s3.amazonaws.com/uploads/articles/em33tfo8udnxi7tu6vvx.png)
结论
我希望你通过这篇文章学到了一些东西(我的第一篇 uWu ^^)。
您可以选择是否更喜欢公开完整模块或仅公开对象。我想这取决于上下文、项目、人员等......
即使它看起来有点“太多”并且需要更多代码和更严格,但从长远来看,这些方法确实增强了控制和质量,以及深入理解(和思考;))代码的每个部分的责任。
更多推荐
所有评论(0)