得墨忒耳定律

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 模块。尊重最少知识的原则

  • 模块(demetermodule1)显式暴露了可以从中使用的内容(显式优于隐式,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 ^^)。

您可以选择是否更喜欢公开完整模块或仅公开对象。我想这取决于上下文、项目、人员等......

即使它看起来有点“太多”并且需要更多代码和更严格,但从长远来看,这些方法确实增强了控制和质量,以及深入理解(和思考;))代码的每个部分的责任。

Logo

学AI,认准AI Studio!GPU算力,限时免费领,邀请好友解锁更多惊喜福利 >>>

更多推荐