“import module”比`from module import function`更好的编码风格吗?

from module import function称为FMIF编码风格。

import module被称为IM编码风格。

from package import module称为FPIM编码风格。

为什么IM + FPIM考虑比FMIF更好的编码风格? (见这个post的灵感这个问题。)

这里有一些标准让我比较喜欢FMIF:

  1. 代码简短:它使我可以使用更短的函数名称,从而帮助坚持80列每行约定。
  2. 可读性: chisquare(...)看起来比scipy.stats.stats.chisquare(...)更具可读性。 虽然这是一个主观标准,但我认为大多数人会同意。
  3. 轻松的redirect:如果我使用FMIF,并由于某种原因在稍后的时间想redirectpython来定义从alt_module而不是module我需要改变只有一行: from alt_module import function 。 如果我使用即时消息,我需要更改许多代码行。

我意识到FPIM会使前两个问题无效,但第三个呢?

我对IM + FPIM可能比FMIF更好的所有原因感兴趣,但是我特别想对这里提到的以下几点进行阐述:

IM的优点:

  1. 轻松嘲笑/注入testing。 (我对嘲笑并不是很熟悉,尽pipe我最近才学会了这个术语的意思,你可以在这里展示代码,说明IM比FMIF更好吗?)
  2. 通过重新定义一些条目来灵活地改变模块的能力。 (我一定是误解了一些东西,因为这似乎是FMIF比IM更好的一个优势,见上面我支持FMIF的第三个原因。)
  3. 在序列化和数据恢复方面可预测和可控的行为。 (我真的不明白IM或FMIF的select如何影响这个问题,请详细说明。)
  4. 我知道FMIF“污染了我的命名空间”,但除了是一个负面的声音,我不明白这是如何以任何具体的方式伤害代码。

PS。 在写这个问题的时候,我收到了一个警告,说这个问题是主观的,很可能会被封闭。 请不要closures它。 我不是在寻找主观意见,而是具体的编码情况,其中IM + FPIM明显好于FMIF。

非常感谢。

您列出的IM / FPIM的底片通常可以通过适当使用as子句来改善。 from some.package import mymodulewithalongname as mymod可以有效地缩短代码并提高其可读性。如果将mymodulewithalongname重命名为明天完全不同的somethingcompletelydifferent ,则可以使用as子句作为单个语句进行编辑。

考虑你的亲FMIF点3(称为Rredirect)与你的亲FPIM点2(称为F的灵活性):R等于促进模块边界完整性的损失,而F加强它。 一个模块中的多个function,类和variables通常是一起工作的:它们不应该独立地转换为不同的含义。 例如,考虑模块random和它的函数seeduniform :如果你只是将其中一个导入到一个不同的模块,那么你会打破seed调用和uniform调用结果之间的正常连接。 当一个模块devise良好,有凝聚力和完整性时,R便于分解模块的边界,这实际上是一个消极的方面 – 它可以使你做更好的事情变得更容易。

反之亦然,F能够实现耦合函数,类和variables的协调切换(通常,通过模块化, 属于一起的实体)。 例如,为了使testing可重复(FPIM pro-point 1),您可以在random模块中嘲讽seedrandom ,如果您的代码遵循FPIM,则全部设置,保证协调; 但是如果你有直接导入函数的代码,你必须search每个这样的模块,并重复一遍又一遍的嘲笑。 使testing完全可重复的通常还需要“协调模拟”date和时间函数 – 如果您在某些模块中使用from datetime import datetime时间,则需要查找并嘲笑它们(以及所有那些from time import time )等等),以确保在系统的各个部分询问“所以现在是几点? 是完全一致的(如果你使用FPIM,你只是嘲笑两个相关的模块)。

我喜欢FPIM,因为通过使用多重限定名称而不是单独限定名称,实际上没有太多附加价值(尽pipe名字和限定名称之间的差别非常 – 您可以通过一个合格的名称获得更多的控制,无论是单独的或乘以,比你可能用一个裸号!)。

嗯,不能把所有的工作时间都用来回应你的每一点 – 你的问题可能应该是六个问题;-)。 我希望这至less解决了“为什么F比R更好”以及一些嘲讽/testing问题 – 归结为保留和提高精心devise的模块化 (通过F)而不是破坏它(通过R)。

关于这个的经典文本经常是来自Fredrik Lundh,effbot。 他的build议: 总是使用import – 除非你不应该。

换句话说,是明智的。 就个人而言,我发现任何几个模块深的东西往往会from xyz import a – 主要的例子是Django模型。 但和其他任何东西一样,这是一个风格问题,你应该有一个一致的 – 特别是像datetime这样的模块,它包含的模块和类被称为相同的东西。 你需要写datetime.datetime.now()或只是datetime.now() ? (在我的代码中,总是前者。)

问题列表中的第1项和第2项似乎是同一个问题。 Python的dynamic特性意味着无论使用哪种方法,都可以很容易地replace模块名称空间中的项目。 如果一个模块中的一个函数引用了另一个函数,那么这就是困难。 在这种情况下,导入模块而不是函数意味着您可以执行module.function_to_replace = myreplacementfunc并且一切工作都是透明的 – 但是通过FPIM和通过IM一样简单。

我也不明白第3项与任何事情有什么关系。 我认为你的第4项是基于一点误解。 你给的方法都不会“污染你的名字空间”。 这是from module import * ,你不知道什么导入,所以函数可以出现在你的代码没有提供给他们的读者来自哪里。 这太可怕了,应该不惜一切代价避免。

像Alex Martelli一样,我喜欢在导入函数时使用。

我做的一件事是在从同一个模块导入的所有函数上使用一些前缀:

 from random import seed as r_seed from random import random as r_random 

r_seedrandom.seed短,但稍微保留了模块边界。 有人随便看看你的代码可以看到r_seed()r_random()并有机会相信他们是相关的。

当然,你总是可以简单地做:

 import random as r 

然后使用r.random()r.seed() ,这可能是这种情况下的理想折衷。 当我从模块导入一个或两个函数时,我只使用前缀技巧。 当我想要使用同一个模块中的很多函数时,我会导入模块,或者用一个缩短名称的模块。

这里有很好的答案(我向他们提出了所有的答案),这里是我对这个问题的想法:

首先,解决你的每一个子弹:

(据称)FMIF的优点:

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

也许,但模块名称通常足够短,所以这是不相关的。 当然,还有datetime ,还有osresys等。而且Python在{ [ ( 。)内部有免费的换行符。对于嵌套模块,IM和FPIM

  • 可读性:chisquare(…)看起来比scipy.stats.stats.chisquare(…)更具可读性。

强烈反对。 在阅读外国代码(或几个月后我自己的代码)时,很难知道每个函数的来源。 限定名称使我无法从2345行到模块声明标题。 而且它也给了你一个上下文chisquare ?那是什么?哦,它是从scypy ?好吧,那么一些math相关的东西呢” 。 而且,再次,您可以scipy.stats.stats as scypyst缩写scipy.stats.stats as scypystscypyst.chisquare(...)足够短,具有合格名称的所有优点。

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

  • 轻松redirect:从altmodule而不是模块重新定义一个函数。

多久你想重新定义一个单一的function,但不是整个模块? 应该保留模块边界和function协调,Alex已经很深入地解释了这一点。 对于大多数(所有?)真实世界的场景,如果alt_module.xalt_module.x的可行替代module.x ,那么alt_module本身可能是module替代品,所以IM和FPIM都像FMIF一样是单线的,提供你as

  • 我意识到FPIM可以通过某种方式来消除前两个问题

事实上, as减轻前两个问题(和第三个)的那个,而不是FPIM。 您也可以使用即时通讯: import some.long.package.path.x as x以获得与FPIM相同的结果。


所以以上都不是FMIF的真正优点。 而我更喜欢IM / FPIM的原因是:

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

另外,如果你需要一个模块中的单个对象,FMIF将会比IM或者FPIM更多的污染你的名字空间,无论你想使用多less个对象,它都会使用一个名字。 而这样的对象将有一个合格的名字,这是一个亲,而不是一个骗局,正如我已经在问题2中说,恕我直言,它提高了可读性。

这一切都归结为一致性,简单性和组织性。 “导入模块,不是对象”是一个很好的,简单的思维模式。

我同意MestreLion这里最多(也是一个upvote)。

我的观点:我经常复习一些我不熟悉的代码,不知道函数来自哪个模块,只是看着这个函数而已,相当令人沮丧。

代码被写入一次并读取很多次,所以可读性和可维护性便于打字。

类似地,通常代码不是为了编码者的利益而编写的,而是为了另一个实体的利益。

你的代码对于那些比你更了解python但对代码不熟悉的人应该是可读的。

完整path导入也可以更好地帮助IDE指出您正在查看的函数或对象的正确来源。

由于所有这些原因和MestreLion指出的原因,我认为最好的做法是导入和使用完整path。