“import module”的编码样式是否比“from module import function”好?

2024-10-01 15:49:02 发布

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

from module import function称为FMIF编码样式。在

import module称为IM编码样式。在

from package import module称为FPIM编码样式。在

为什么IM+FPIM被认为是比FMIF更好的编码风格?(关于这个问题的灵感,请参见this post。)

以下是一些让我更喜欢FMIF而不是IM的标准:

  1. 代码简短:它允许我使用较短的函数名,从而有助于坚持每行80列的惯例。 在
  2. 可读性:chisquare(...)scipy.stats.stats.chisquare(...)更具可读性。虽然这是一个主观标准,但我认为大多数人都会同意。 在
  3. 重定向的易用性:如果我使用FMIF,并且在以后某个时候由于某种原因想要重定向python以从alt_module而不是module来定义function,我只需要更改一行:from alt_module import function。如果我使用IM,我需要更改许多行代码。 在
我知道FPIM在某种程度上否定了前两个问题,但第三个问题呢?

我对IM+FPIM可能比FMIF更好的所有原因感兴趣, 但我特别想详细说明以下几点mentioned here

IM的优点:

  1. 易于在测试中模拟/注入。)我不太熟悉嘲弄,虽然我最近才知道这个词的意思。你能在这里展示一下IM比FMIF更好的代码吗?) 在
  2. 模块通过重新定义一些条目来灵活更改的能力。(我一定是误解了什么,因为这似乎是FMIF相对于IM的优势。请参阅上文我支持FMIF的第三个理由。) 在
  3. 数据序列化和恢复的可预测和可控行为。(我真的不明白IM或FMIF的选择如何影响这个问题。请详细说明。)
  4. 我理解FMIF“污染了我的名称空间”,但除了它是一个听起来很负面的短语之外,我不明白这对代码有何具体的伤害。 在
在写这个问题的时候,我收到了一个警告,这个问题似乎是主观的,很可能会结束。请不要关上它。我不是在寻找主观的意见,而是在IM+FPIM明显优于FMIF的具体编码情况下。

非常感谢。在


Tags: 代码fromimport编码标准statsfunction样式
3条回答

关于这一点的经典文本,经常是来自弗雷德里克伦德,efffbot。他的建议是:always use import-除非你不该这样做

换句话说,要理智。就我个人而言,我发现任何深度为多个模块的东西都倾向于通过from x.y.z import a导入——主要的例子是Django模型。但是和其他任何东西一样,这是一个风格问题,你应该有一个一致的风格,尤其是像datetime这样的模块,其中模块和它包含的类都被称为同一个东西。你需要写datetime.datetime.now()还是只写datetime.now()?(在我的代码中,总是前者。)

你的问题清单中的第1项和第2项似乎是同一问题。Python的动态特性意味着无论使用哪种方法,替换模块名称空间中的项都非常简单。如果一个模块中的一个函数引用另一个函数,而这正是您想要模仿的那个函数,那么困难就来了。在本例中,导入模块而不是函数意味着您可以执行module.function_to_replace = myreplacementfunc并且所有操作都是透明的—但是通过FPIM和通过IM一样容易。在

我也不明白第3项是怎么跟任何事情有关的。不过,我认为你的第4项是基于一点误解。您提供的任何方法都不会“污染您的命名空间”。所做的是from module import *,在这里你根本不知道你要导入什么,因此函数可以出现在你的代码中,而不会给读者提供它们来自何处的线索。这太可怕了,应该不惜一切代价避免。在

这里有很好的答案(我都投了赞成票),下面是我对这个问题的看法:

首先,解决每个要点:

(据称)FMIF的优点:

  • 代码简短:更短的函数名有助于坚持每行80列。

也许吧,但是模块名通常很短,所以这并不相关。当然,这里有datetime,还有osresys等等,Python在{ [ (内有自由换行符。对于嵌套模块,IM和FPIM中都有as

  • 可读性:chisquare(…)比scipy.stats.stats.chisquare(…)。

强烈反对。当阅读外国代码(或几个月后我自己的代码)时,很难知道每个函数来自何处。限定名避免了我从第2345行到模块声明头的来回转换。它还提供了上下文chisquare?那是什么?哦,是从^{来的?好吧,一些数学相关的东西然后“。再说一次,你总是可以缩写scipy.stats.stats as scypystscypyst.chisquare(...)足够短,具有限定名的所有优点。在

import os.path as osp是另一个很好的例子,考虑到在一个单独的调用中将3个或更多的函数链在一起是很常见的:join(expanduser(),basename(splitext())等

  • 易于重定向:从altmodule而不是module对函数进行一行重新定义。

您希望重新定义单个函数而不是整个模块的频率?应该保留模块边界和功能协调,Alex已经对此进行了深入的解释。对大多数人来说在现实世界中,如果alt_module.xmodule.x的可行替代品,那么{}本身可能是{}的替代品,因此IM和FPIM都是与FMIF一样的一行程序,前提是使用as。在

  • 我意识到FPIM在某种程度上否定了前两个问题。。。

实际上,as是缓解前2个问题(和第3个问题)的,而不是FPIM。您也可以使用IM来实现这一点:import some.long.package.path.x as x得到与FPIM相同的结果。在


所以以上这些都不是FMIF的优点。我喜欢IM/FPIM的原因是:

为了简单和一致,当我导入IM或FPIM时,我总是导入一个模块,而不是从模块中导入对象。记住FMIF可以(ab-)用于导入函数、类、变量甚至其他模块!想想from somemodule import sys, somevar, os, SomeClass, datetime, someFunc的混乱。在

另外,如果你想从一个模块中得到一个以上的对象,那么FMIF会比IM或FPIM污染你的命名空间更严重,不管你想使用多少个对象,FMIF都会使用一个名称。这样的对象将有一个限定的名称,这是一个优点,而不是缺点:正如我在第2期中所说的,IMHO a it提高了的可读性。在

归根结底是一致性、简单性和组织性。“导入模块,而不是对象”是一个好的、容易理解的思维模式。在

您为IM/FPIM列出的否定项通常可以通过适当使用as子句来改善。from some.package import mymodulewithalongname as mymod可以有效地缩短代码并增强其可读性,如果明天将mymodulewithalongname重命名为somethingcompletelydifferent,则{}子句可以作为单个语句进行编辑。在

考虑一下pro-FMIF第3点(重定向时称为R)与pro-FPIM第2点(灵活性称之为F):R相当于促进了模块边界完整性的丧失,而F加强了它。一个模块中的多个函数、类和变量通常是一起工作的:它们不应该被独立地转换成不同的含义。例如,考虑模块random及其函数seed和{}:如果只将其中一个的导入切换到另一个模块,则会中断对seed的调用和对{}调用结果之间的正常连接。当一个模块设计得很好,具有内聚性和完整性时,R打破模块边界的便利性实际上是一个负面的因素——它使你更容易做一些你不该做的事情。在

反之亦然,F使耦合函数、类和变量(因此,一般来说,通过模块化,属于在一起的实体)能够进行协调切换。例如,为了使测试具有可重复性(FPIM pro point 1),您可以模拟seed和{}模块中的seed和{},如果您的代码遵循FPIM,那么您就已经设置好了,可以保证协调;但是如果您有直接导入函数的代码,则必须搜索每个这样的模块,并一遍又一遍地重复模拟。使测试完全可重复通常还需要对日期和时间函数进行“协调模拟”——如果在某些模块中使用from datetime import datetime,则需要找到并模拟所有这些函数(以及所有执行from time import time的模块,以此类推),以确保当系统的各个部分询问“现在几点了?”时收到的所有时间完全一致(如果使用FPIM,只需模拟两个相关模块)。在

我喜欢FPIM,因为使用一个multiply限定名而不是一个单独的限定名并没有太多的附加值(虽然裸名和限定名之间的区别是巨大的——因此,使用限定名的控制力要比使用限定名(无论是单个还是乘法)要多得多一个赤裸裸的名字。在

好吧,不能把所有的工作时间都用来回答你的每一个问题——你的问题应该是六个问题;—)。我希望这至少能解决“为什么F比R好”和一些模拟/测试问题——它归结为保存和增强设计良好的模块化(通过F),而不是破坏它(通过R)。在

相关问题 更多 >

    热门问题