将from module import function
称为FMIF编码样式。
将import module
称为IM编码风格。
让from package import module
称为FPIM编码风格。
为什么IM + FPIM被认为是比FMIF更好的编码风格? (有关此问题的灵感,请参阅this post。)
以下是一些让我更喜欢FMIF而非IM的标准:
chisquare(...)
似乎比scipy.stats.stats.chisquare(...)
更具可读性。虽然这是一个主观标准,但我认为大多数人会同意。
function
而不是alt_module
定义module
我需要更改一行:from alt_module import function
。如果我使用IM,我需要更改许多行代码。
我对IM + FPIM可能比FMIF更好的所有原因感兴趣, 但特别是,我有兴趣详细阐述以下几点mentioned here:
IM的优点:
非常感谢。
答案 0 :(得分:44)
您为IM / FPIM列出的否定通常可以通过适当使用as
子句来改善。 from some.package import mymodulewithalongname as mymod
可以有效缩短代码并增强其可读性,如果明天将mymodulewithalongname
重命名为somethingcompletelydifferent
,as
子句可以用作单个语句进行编辑。< / p>
考虑你的pro-FMIF第3点(称之为R用于重定向)与你的pro-FPIM第2点(称之为F的灵活性):R相当于促进模块边界完整性的丧失,而F则强化它。模块中的多个函数,类和变量通常旨在协同工作:它们不应独立地切换到不同的含义。例如,考虑模块random
及其函数seed
和uniform
:如果您要将其中一个的导入切换到另一个模块,那么您将打破正常连接在致电seed
和调用uniform
的结果之间。当一个模块设计得很好,具有凝聚力和完整性时,R可以帮助打破模块的界限,这实际上是一个负面因素 - 它可以让你更容易做出更好的事情而不是。
反之亦然,F是通过模块化实现协调切换耦合函数,类和变量(通常是属于的实体)的功能。例如,为了使测试可重复(FPIM pro-point 1),您在seed
模块中模拟了random
和random
,如果您的代码遵循FPIM,那么您已全部设置,协调保证;但是如果你有直接导入函数的代码,你必须搜索每个这样的模块并反复重复模拟。使测试完全可重复通常还需要“协调模拟”日期和时间函数 - 如果在某些模块中使用from datetime import datetime
,则需要查找并模拟它们(以及所有执行from time import time
的人,等等)确保系统的各个部分询问“现在几点了?”时收到的所有时间。完全一致(如果你使用FPIM,你只需要模拟两个相关的模块)。
我喜欢FPIM,因为使用乘法限定名称而不是单一合格名称实际上没有多少附加价值(而裸名和限定名称之间的区别是巨大 - 你得到所以更多的控制与一个合格的名字,无论是单独的还是多次的,比你可能用一个名字!)。
好吧,不能把所有工作日用于回应你的每一点 - 你的问题可能应该是六个问题;-)。我希望这至少解决“为什么F比R更好”和一些模拟/测试问题 - 它归结为保留和增强精心设计的模块化(通过F)而不是破坏它(通过R)。答案 1 :(得分:16)
关于这一点的经典文本,经常来自Fredrik Lundh,即effbot。他的建议是: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 *
,你根本不知道你要导入什么,因此函数可以出现在你的代码中,而不会给读者带来任何线索。这太可怕了,应该不惜一切代价避免。
答案 2 :(得分:6)
这里有很棒的答案(我全都赞成),以下是我对此事的看法:
首先,解决每个子弹:
(据称)FMIF的优点:
也许,但模块名称通常很短,所以这不相关。当然,还有datetime
,还有os
,re
,sys
等。而Python在{ [ (
内有免费换行符。对于嵌套模块,IM和FPIM中始终存在as
非常不同意。在阅读外国代码(或几个月后我自己的代码)时,很难知道每个函数的来源。合格的名称使我免于从2345行到模块声明标题。它还为你提供上下文:“chisquare
?这是什么?哦,它来自scypy
?好吧,一些数学相关的东西然后” 。而且,您可以再次缩写scipy.stats.stats as scypyst
。 scypyst.chisquare(...)
足够短,并且具有合格名称的所有好处。
import os.path as osp
是另一个很好的例子,考虑到在一次调用中将3个或更多函数链接在一起非常常见:join(expanduser(),basename(splitext()))等。
您想要重新定义单个功能但不是整个模块的频率?应保留模块边界和功能协调,Alex已经深入解释了这一点。对于大多数(全部?)真实场景,如果alt_module.x
是module.x
的可行替代品,则alt_module
本身可能是module
的替代品,因此IM和FPIM就像FMIF一样,只要你使用as
。
实际上,as
是减轻前两个问题(和第三个)而不是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更多地污染您的命名空间,无论您要使用多少个对象,它都将使用单个名称。这样的对象将有一个限定的名称,这是一个专业人士,而不是一个骗子:正如我在问题2中所说,恕我直言,它提高可读性。
这一切都归结为一致性,简洁性,组织性。 “导入模块,而不是对象”是一个很好的,易于思考的模型。
答案 3 :(得分:5)
与Alex Martelli一样,我喜欢在导入函数时使用as
。
我做的一件事是在从同一模块导入的所有函数上使用一些前缀:
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()
,这可能是此案例的理想折衷方案。当我从模块导入一个或两个函数时,我只使用前缀技巧。当我想使用同一模块中的许多函数时,我将导入模块,可能使用as
来缩短名称。
答案 4 :(得分:1)
我最同意MestreLion(这是一个upvote)。
我的观点:我经常查看我不熟悉的代码,并且不知道函数来自于查看函数的功能是非常令人沮丧的。
代码编写一次并多次读取,因此可读性和可维护性胜过打字的难易程度。
类似地,代码通常是 not 是为了编码人员的利益而编写的,但是为了另一个实体的利益。
对于比您更了解python的人,您的代码应该是可读的,但是对代码不熟悉。
完整路径导入还可以更好地帮助IDE指出您正在查看的功能或对象的正确来源。
由于所有这些原因以及MestreLion注意到的原因,我得出结论,导入和使用完整路径是最佳做法。