“import module”比`from module import function`更好的编码风格吗?
让from module import function
称为FMIF编码风格。
让import module
被称为IM编码风格。
让from package import module
称为FPIM编码风格。
为什么IM + FPIM考虑比FMIF更好的编码风格? (见这个post的灵感这个问题。)
这里有一些标准让我比较喜欢FMIF:
- 代码简短:它使我可以使用更短的函数名称,从而帮助坚持80列每行约定。
- 可读性:
chisquare(...)
看起来比scipy.stats.stats.chisquare(...)
更具可读性。 虽然这是一个主观标准,但我认为大多数人会同意。 - 轻松的redirect:如果我使用FMIF,并由于某种原因在稍后的时间想redirectpython来定义从
alt_module
而不是module
我需要改变只有一行:from alt_module import function
。 如果我使用即时消息,我需要更改许多代码行。
我意识到FPIM会使前两个问题无效,但第三个呢?
我对IM + FPIM可能比FMIF更好的所有原因感兴趣,但是我特别想对这里提到的以下几点进行阐述:
IM的优点:
- 轻松嘲笑/注入testing。 (我对嘲笑并不是很熟悉,尽pipe我最近才学会了这个术语的意思,你可以在这里展示代码,说明IM比FMIF更好吗?)
- 通过重新定义一些条目来灵活地改变模块的能力。 (我一定是误解了一些东西,因为这似乎是FMIF比IM更好的一个优势,见上面我支持FMIF的第三个原因。)
- 在序列化和数据恢复方面可预测和可控的行为。 (我真的不明白IM或FMIF的select如何影响这个问题,请详细说明。)
- 我知道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
和它的函数seed
和uniform
:如果你只是将其中一个导入到一个不同的模块,那么你会打破seed
调用和uniform
调用结果之间的正常连接。 当一个模块devise良好,有凝聚力和完整性时,R便于分解模块的边界,这实际上是一个消极的方面 – 它可以使你做更好的事情变得更容易。
反之亦然,F能够实现耦合函数,类和variables的协调切换(通常,通过模块化, 属于一起的实体)。 例如,为了使testing可重复(FPIM pro-point 1),您可以在random
模块中嘲讽seed
和random
,如果您的代码遵循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_seed
比random.seed
短,但稍微保留了模块边界。 有人随便看看你的代码可以看到r_seed()
和r_random()
并有机会相信他们是相关的。
当然,你总是可以简单地做:
import random as r
然后使用r.random()
和r.seed()
,这可能是这种情况下的理想折衷。 当我从模块导入一个或两个函数时,我只使用前缀技巧。 当我想要使用同一个模块中的很多函数时,我会导入模块,或者用一个缩短名称的模块。
这里有很好的答案(我向他们提出了所有的答案),这里是我对这个问题的想法:
首先,解决你的每一个子弹:
(据称)FMIF的优点:
- 代码简短:较短的函数名称有助于坚持80列每行。
也许,但模块名称通常足够短,所以这是不相关的。 当然,还有datetime
,还有os
, re
, sys
等。而且Python在{ [ (
。)内部有免费的换行符。对于嵌套模块,IM和FPIM
- 可读性:chisquare(…)看起来比scipy.stats.stats.chisquare(…)更具可读性。
强烈反对。 在阅读外国代码(或几个月后我自己的代码)时,很难知道每个函数的来源。 限定名称使我无法从2345行到模块声明标题。 而且它也给了你一个上下文 : “ chisquare
?那是什么?哦,它是从scypy
?好吧,那么一些math相关的东西呢” 。 而且,再次,您可以scipy.stats.stats as scypyst
缩写scipy.stats.stats as scypyst
。 scypyst.chisquare(...)
足够短,具有合格名称的所有优点。
import os.path as osp
是另一个很好的例子,考虑到在单个调用中将3个或更多的函数链接在一起非常常见:join(expanduser(),basename(splitext()))等等
- 轻松redirect:从altmodule而不是模块重新定义一个函数。
多久你想重新定义一个单一的function,但不是整个模块? 应该保留模块边界和function协调,Alex已经很深入地解释了这一点。 对于大多数(所有?)真实世界的场景,如果alt_module.x
是alt_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。