“导入模块”的编码风格是否优于“从模块导入功能”?

时间:2022-12-20 02:45:47

Let from module import function be called the FMIF coding style.

让模块导入函数被称为FMIF编码风格。

Let import module be called the IM coding style.

让导入模块被称为IM编码样式。

Let from package import module be called the FPIM coding style.

从包导入模块被称为FPIM编码风格。

Why is IM+FPIM considered a better coding style than FMIF? (See this post for the inspiration for this question.)

为什么IM+FPIM被认为是比FMIF更好的编码风格?(这个问题的灵感来自这篇文章。)

Here are some criteria which lead me to prefer FMIF over IM:

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

  1. Shortness of code: It allows me to use shorter function names and thus help stick to the 80 columns-per-line convention.
  2. 代码的简洁性:它允许我使用更短的函数名,因此有助于坚持每行80列的约定。
  3. Readability: chisquare(...) appears more readable than scipy.stats.stats.chisquare(...). Although this is a subjective criterion, I think most people would agree.
  4. 可读性:chisquare(…)看起来比scipy.stats.stats.chisquare(…)更具可读性。虽然这是一个主观标准,但我想大多数人都会同意。
  5. Ease of redirection: If I use FMIF and for some reason at some later time want to redirect python to define function from alt_module instead of module I need to change just one line: from alt_module import function. If I were to use IM, I'd need to change many lines of code.
  6. 重定向容易:如果我使用FMIF,并且由于某些原因在以后想要重定向python以从alt_module定义函数,而不是模块,那么我只需要更改一行:从alt_module导入函数。如果我要使用IM,我需要修改很多行代码。
I realize FPIM goes some way to nullifying the first two issues, but what about the third?

I am interested in all reasons why IM+FPIM may be better than FMIF, but in particular, I'd be interested in elaboration on the following points mentioned here:

我对IM+FPIM优于FMIF的所有原因都很感兴趣,但特别想对这里提到的以下几点进行阐述:

Pros for IM:

我的优点:

  1. ease of mocking/injecting in tests. (I am not very familiar with mocking, though I recently learned what the term means. Can you show code which demonstrates how IM is better than FMIF here?)
  2. 在测试中容易模仿/注入。(我不太熟悉“嘲笑”这个词,虽然我最近才知道它的意思。你能显示代码来演示IM如何比FMIF更好吗?
  3. ability for a module to change flexibly by redefining some entries. (I must be misunderstanding something, because this seems to be an advantage of FMIF over IM. See my third reason in favor of FMIF above.)
  4. 模块通过重新定义一些条目来灵活地更改的能力。我一定是误解了什么,因为这似乎是FMIF对IM的优势。看看我支持FMIF的第三个理由。
  5. predictable and controllable behavior on serialization and recovery of your data. (I really don't understand how the choice of IM or FMIF affects this issue. Please elaborate.)
  6. 数据序列化和恢复的可预测和可控行为。(我真的不明白如何选择IM或FMIF来影响这个问题。请详细说明。)
  7. I understand that FMIF "pollutes my namespace", but beyond being a negative-sounding phrase, I don't appreciate how this hurts the code in any concrete way.
  8. 我理解FMIF“污染了我的名称空间”,但除了一个听起来很负面的短语之外,我不理解这对代码有什么具体的伤害。
PS. While writing this question I received a warning that the question appears subjective and is likely to be closed. Please don't close it. I'm not looking for subjective opinion, but rather concrete coding situations where IM+FPIM is demonstrably better than FMIF.

Many thanks.

多谢。

5 个解决方案

#1


40  

The negatives you list for IM/FPIM can often be ameliorated by appropriate use of an as clause. from some.package import mymodulewithalongname as mymod can usefully shorten your code and enhance its readability, and if you rename mymodulewithalongname to somethingcompletelydifferent tomorrow, the as clause can be used as a single statement to edit.

你为IM/FPIM列出的缺点通常可以通过适当地使用as子句得到改善。从一些。包导入mymodulewithalongname作为mymod可以有效地缩短您的代码并增强其可读性,如果您将mymodulewithalongname重命名为完全不同的明天,则可以将as子句作为单个语句进行编辑。

Consider your pro-FMIF point 3 (call it R for redirection) vs your pro-FPIM point 2 (call it F for flexibility): R amounts to facilitating the loss of integrity of module boundaries, while F strenghtens it. Multiple functions, classes and variables in a module are often intended to work together: they should not be independently switched to different meanings. For example, consider module random and its functions seed and uniform: if you were to switch the import of just one of them to a different module, then you'd break the normal connection between calls to seed and results of calls to uniform. When a module is well designed, with cohesion and integrity, R's facilitation of breaking down the module's boundaries is actually a negative -- it makes it easier to do something you're better off not doing.

考虑你的前fmif点3(用R表示重定向)和前fpim点2(用F表示灵活性):R表示促进模块边界完整性的丧失,而F表示增强。模块中的多个函数、类和变量通常是要一起工作的:它们不应该被独立地转换为不同的含义。例如,考虑模块random及其函数seed和uniform:如果您将其中一个模块的导入切换到另一个模块,那么您将断开对seed的调用与调用校服的结果之间的正常连接。当一个模块设计得很好,具有内聚性和完整性,R简化模块边界的过程实际上是一个负面的——它会让你更容易做一些你最好不要做的事情。

Vice versa, F is what enables coordinated switching of coupled functions, classes, and variables (so, generally, of entities that belong together, by modularity). For example, to make testing repeatable (FPIM pro-point 1), you mock both seed and random in the random module, and if your code follows FPIM, you're all set, coordination guaranteed; but if you have code that has imported the functions directly, you have to hunt down each such module and repeat the mocking over and over and over again. Making tests perfectly repeatable typically also requires "coordinated mocking" of date and time functions -- if you use from datetime import datetime in some modules, you need to find and mock them all (as well as all those doing from time import time, and so forth) to ensure that all the times received when the various parts of the system ask "so what time is it now?" are perfectly consistent (if you use FPIM, you just mock the two relevant modules).

反之亦然,F使耦合函数、类和变量(通常来说,通过模块化,属于一起的实体)的协调切换成为可能。例如,为了使测试可重复(FPIM pro-point 1),您在随机模块中模拟种子和随机,如果您的代码遵循FPIM,那么您就已经设置好了,保证了协调;但是,如果您有直接导入函数的代码,则必须查找每个这样的模块,并反复重复mock操作。使测试完全可重复通常也需要日期和时间函数的“协调嘲笑”——如果你使用从datetime导入datetime在一些模块,你需要找到和模拟他们(以及所有那些做导入时间,等等)来确保每一次收到当系统的各个部分问“现在几点了?”完全一致(如果你使用FPIM,你只是模拟的两个相关模块)。

I like FPIM, because there's really not much added value by using a multiply qualified name rather than a singly qualified one (while the difference between barenames and qualified names is huge -- you get so much more control with a qualified name, be it singly or multiply, than you possibly ever can with a barename!).

我喜欢FPIM,因为其实没有多少附加值用乘限定名称,而不是一个单独合格(虽然barenames和限定名的区别是巨大的——你得到更多控制限定名,无论是单独或繁殖,比你可能可以用barename !)。

Ah well, can't devote all of the working day to responding to each and every one of your points -- your question should probably be half a dozen questions;-). I hope this at least addresses "why is F better than R" and some of the mocking/testing issues -- it boils down to preserving and enhancing well-designed modularity (via F) rather than undermining it (via R).

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

#2


16  

The classic text on this, as so often, is from Fredrik Lundh, the effbot. His advice: always use import - except when you shouldn't.

关于这个问题的经典文本,一如既往地,来自于弗德里克·伦德(Fredrik Lundh), effbot。他的建议是:永远使用进口——除非你不应该这么做。

In other words, be sensible. Personally I find that anything that's several modules deep tends to get imported via from x.y.z import a - the main example being Django models. But as much as anything else it's a matter of style, and you should have a consistent one - especially with modules like datetime, where both the module and the class it contains are called the same thing. Do you need to write datetime.datetime.now() or just datetime.now()? (In my code, always the former.)

换句话说,要明智。就我个人而言,我发现任何深入的模块都倾向于通过x.y导入。z导入a -主要示例是Django模型。但与其他任何东西一样,这是一个风格问题,您应该有一个一致的风格——特别是对于datetime这样的模块,它包含的模块和类都被称为相同的东西。您是否需要写入datetime.datetime.now()或datetime.now()?(在我的代码中,总是前者。)

Items 1 and 2 in your list of questions seem to be the same issue. Python's dynamic nature means it is fairly simple to replace an item in a module's namespace no matter which of the methods you use. The difficulty comes if one function in a module refers to another, which is the one you want to mock. In this case, importing the module rather than the functions means you can do module.function_to_replace = myreplacementfunc and everything works transparently - but that is as easy to do via FPIM as it is via IM.

在你的问题列表中,第1和第2项似乎是相同的问题。Python的动态特性意味着,无论使用哪种方法,替换模块名称空间中的项都相当简单。如果模块中的一个函数引用了另一个函数,那么就会出现问题,这就是您想要模拟的函数。在这种情况下,导入模块而不是函数意味着可以执行模块。function_to_replace = myreplacementfunc和所有的工作都是透明的——但是通过FPIM,这就像通过IM一样简单。

I also don't understand how item 3 has anything to do with anything. I think your item 4, however, is based on a bit of a misunderstanding. None of the methods you give will 'pollute your namespace'. What does do that is from module import *, where you have no idea at all what you're importing and so functions can appear in your code with no clue given to the reader where they came from. That's horrible, and should be avoided at all costs.

我也不明白第3项与任何事情有什么关系。我认为你的第4项,然而,是基于一点误解。您提供的任何方法都不会“污染您的名称空间”。它的作用是来自模块导入*,在那里你根本不知道你要导入什么,所以函数可以出现在你的代码中,却不知道它们来自哪里。这太可怕了,应该不惜一切代价避免。

#3


5  

Like Alex Martelli, I am fond of using as when importing a function.

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

One thing I have done is to use some prefix on all the functions that were imported from the same module:

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

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

r_seed is shorter to type than random.seed but somewhat preserves the module boundaries. Someone casually looking at your code can see r_seed() and r_random() and have a chance to grok that they are related.

r_seed的类型比random要短。种子但在某种程度上保留了模块边界。随意查看代码的人可以看到r_seed()和r_random(),并有机会摸索出它们是相关的。

Of course, you can always simply do:

当然,你可以简单地做到:

import random as r

and then use r.random() and r.seed(), which may be the ideal compromise for this case. I only use the prefix trick when I'm importing one or two functions from a module. When I want to use many functions from the same module, I'll import the module, perhaps with an as to shorten the name.

然后使用r.random()和r.seed(),这可能是理想的折衷方案。我只在从模块导入一两个函数时使用前缀技巧。当我想要在同一个模块中使用多个函数时,我将导入模块,可能使用一个来缩短名称。

#4


5  

Great answers here (I upvoted them all), and here are my thoughts on this matter:

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

First, addressing each of your bullets:

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

(Allegedly) Pros of FMIF:

(据说)FMIF的优点:

  • Shortness of code: shorter function names help stick to the 80 columns-per-line.
  • 代码简短:更短的函数名有助于每行保持80列。

Perhaps, but module names are usually short enough so this is not relevant. Sure, there's datetime, but also os, re, sys, etc. And Python has free line breaks inside { [ (. And for nested modules there's always as in both IM and FPIM

也许,但是模块名通常足够短,所以这是不相关的。当然,有datetime,也有os、re、sys等。Python在{[()中有空闲行。对于嵌套模块,IM和FPIM中都有

  • Readability: chisquare(...) appears more readable than scipy.stats.stats.chisquare(...).
  • 可读性:chisquare(…)看起来比scipy.stats.stats.chisquare(…)更具可读性。

Strongly disagree. When reading foreign code (or my own code after a few months) it's hard to know where each function comes from. Qualified names saves me from going back and forth from line 2345 to module declarations header. And it also gives you context: "chisquare? What's that? Oh, it's from scypy? Ok, some math-related stuff then". And, once again, you can always abbreviate scipy.stats.stats as scypyst. scypyst.chisquare(...) is short enough with all benefits of a qualified name.

强烈反对。当阅读外文代码(或几个月后我自己的代码)时,很难知道每个函数来自哪里。合格的名称使我不必在第2345行和模块声明头之间来回切换。它也给你上下文:“chisquare?”那是什么?从scypy哦,是吗?好的,一些数学相关的东西"同样,您也可以缩写scipy.stats。scypyst统计数据。chisquare(…)足够短,拥有一个合格名称的所有好处。

import os.path as osp is another good example, considering it's very common to chain 3 or more of its functions together in a single call: join(expanduser(),basename(splitext())) etc.

进口操作系统。path作为osp是另一个很好的例子,考虑到将3或更多的函数链接在一个调用中是很常见的:join(expanduser()、basename(splitext()))等。

  • Ease of redirection: one-line redefinition of a function from altmodule instead of module.
  • 易于重定向:从altmodule而不是模块重新定义函数的一行代码。

How often you want to redefine a single function but not whole module? Module boundaries and function coordination should be preserved, and Alex already explained this in great depth. For most (all?) real-world scenarios, if alt_module.x is a viable replacement for module.x, then probably alt_module itself is a drop in alternative for module, so both IM and FPIM are one-liners just like FMIF, provided you use as.

您希望重新定义单个函数而不是整个模块的频率是多少?模块边界和功能协调需要保留,Alex已经对此做了深入的说明。对于大多数真实场景(全部?),如果是alt_module。x是一个可行的模块替代品。所以IM和FPIM都是一行程序,就像FMIF一样,只要您使用as。

  • I realize FPIM goes some way to nullifying the first two issues...
  • 我意识到FPIM在某种程度上取消了前两个问题……

Actually, as is the one that mitigates the first 2 issues (and the 3rd), not FPIM. You can use IM for that too: import some.long.package.path.x as x for the same result as FPIM.

实际上,缓解前两个问题(和第三个问题)的是FPIM,而不是FPIM。你也可以用IM: import some.long.pack .path。x = x = FPIM。


So none of the above are really pros of FMIF. And the reasons I prefer IM/FPIM are:

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

For the sake of simplicity and consistency, when I import something, either IM or FPIM, I'm always importing a module, not an object from a module. Remember FMIF can be (ab-)used to import functions, classes, variables, or even other modules! Think about the mess of from somemodule import sys, somevar, os, SomeClass, datetime, someFunc.

为了简单和一致,当我导入一些东西时,无论是IM还是FPIM,我总是从模块中导入一个模块,而不是对象。记住,FMIF可以(ab-)用于导入函数、类、变量,甚至其他模块!想想那些从somemodule导入系统、somevar、os、SomeClass、datetime、someFunc中产生的混乱。

Also, if you want more than a single object from a module, FMIF will pollute your namespace more than IM or FPIM, which will use a single name no matter how many objects you want to use. And such objects will have a qualified name, which is a pro, not a con: as I've said in issue 2, IMHO a it improves readability.

此外,如果您想从模块中获得多个对象,那么FMIF会比IM或FPIM更容易污染您的命名空间,无论您想要使用多少对象,FMIF都会使用一个名称。这样的对象将有一个限定的名称,这是一个专业名称,而不是一个缺点:正如我在第2期中所说,IMHO a将提高可读性。

it all comes down to consistency, simplicity, organization. "Import modules, not objects" is a good, easy mind model to stick with.

这一切都归结于一致性、简单性和组织性。“导入模块,而不是对象”是一个很好的、容易坚持的思想模型。

#5


1  

I agree with MestreLion the most here (and so an upvote).

我最同意MestreLion的观点(所以我投了赞成票)。

My perspective: I review code frequently that I am unfamiliar with, and not knowing what module a function is coming from just looking at the function is quite frustrating.

我的观点是:我经常检查我不熟悉的代码,不知道一个函数的模块来自于什么函数,这让我很沮丧。

Code is written once and read many times, and so readability and maintainability trumps ease of typing.

代码一次编写,多次读取,因此可读性和可维护性胜过易于输入。

In a similar vein, typically code is not being written for the benefit of the coder, but for the benefit of another entity.

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

Your code should be readable to someone who knows python better than you, but is unfamiliar with the code.

对于比您更了解python但不熟悉代码的人来说,您的代码应该是可读的。

Full path imports can also better help IDE's point you at the correct source of the function or object you're looking at.

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

For all of these reasons and the reasons MestreLion noted, I conclude that it is best practice to import and use the full path.

由于所有这些原因和MestreLion指出的原因,我认为导入和使用完整路径是最佳实践。

#1


40  

The negatives you list for IM/FPIM can often be ameliorated by appropriate use of an as clause. from some.package import mymodulewithalongname as mymod can usefully shorten your code and enhance its readability, and if you rename mymodulewithalongname to somethingcompletelydifferent tomorrow, the as clause can be used as a single statement to edit.

你为IM/FPIM列出的缺点通常可以通过适当地使用as子句得到改善。从一些。包导入mymodulewithalongname作为mymod可以有效地缩短您的代码并增强其可读性,如果您将mymodulewithalongname重命名为完全不同的明天,则可以将as子句作为单个语句进行编辑。

Consider your pro-FMIF point 3 (call it R for redirection) vs your pro-FPIM point 2 (call it F for flexibility): R amounts to facilitating the loss of integrity of module boundaries, while F strenghtens it. Multiple functions, classes and variables in a module are often intended to work together: they should not be independently switched to different meanings. For example, consider module random and its functions seed and uniform: if you were to switch the import of just one of them to a different module, then you'd break the normal connection between calls to seed and results of calls to uniform. When a module is well designed, with cohesion and integrity, R's facilitation of breaking down the module's boundaries is actually a negative -- it makes it easier to do something you're better off not doing.

考虑你的前fmif点3(用R表示重定向)和前fpim点2(用F表示灵活性):R表示促进模块边界完整性的丧失,而F表示增强。模块中的多个函数、类和变量通常是要一起工作的:它们不应该被独立地转换为不同的含义。例如,考虑模块random及其函数seed和uniform:如果您将其中一个模块的导入切换到另一个模块,那么您将断开对seed的调用与调用校服的结果之间的正常连接。当一个模块设计得很好,具有内聚性和完整性,R简化模块边界的过程实际上是一个负面的——它会让你更容易做一些你最好不要做的事情。

Vice versa, F is what enables coordinated switching of coupled functions, classes, and variables (so, generally, of entities that belong together, by modularity). For example, to make testing repeatable (FPIM pro-point 1), you mock both seed and random in the random module, and if your code follows FPIM, you're all set, coordination guaranteed; but if you have code that has imported the functions directly, you have to hunt down each such module and repeat the mocking over and over and over again. Making tests perfectly repeatable typically also requires "coordinated mocking" of date and time functions -- if you use from datetime import datetime in some modules, you need to find and mock them all (as well as all those doing from time import time, and so forth) to ensure that all the times received when the various parts of the system ask "so what time is it now?" are perfectly consistent (if you use FPIM, you just mock the two relevant modules).

反之亦然,F使耦合函数、类和变量(通常来说,通过模块化,属于一起的实体)的协调切换成为可能。例如,为了使测试可重复(FPIM pro-point 1),您在随机模块中模拟种子和随机,如果您的代码遵循FPIM,那么您就已经设置好了,保证了协调;但是,如果您有直接导入函数的代码,则必须查找每个这样的模块,并反复重复mock操作。使测试完全可重复通常也需要日期和时间函数的“协调嘲笑”——如果你使用从datetime导入datetime在一些模块,你需要找到和模拟他们(以及所有那些做导入时间,等等)来确保每一次收到当系统的各个部分问“现在几点了?”完全一致(如果你使用FPIM,你只是模拟的两个相关模块)。

I like FPIM, because there's really not much added value by using a multiply qualified name rather than a singly qualified one (while the difference between barenames and qualified names is huge -- you get so much more control with a qualified name, be it singly or multiply, than you possibly ever can with a barename!).

我喜欢FPIM,因为其实没有多少附加值用乘限定名称,而不是一个单独合格(虽然barenames和限定名的区别是巨大的——你得到更多控制限定名,无论是单独或繁殖,比你可能可以用barename !)。

Ah well, can't devote all of the working day to responding to each and every one of your points -- your question should probably be half a dozen questions;-). I hope this at least addresses "why is F better than R" and some of the mocking/testing issues -- it boils down to preserving and enhancing well-designed modularity (via F) rather than undermining it (via R).

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

#2


16  

The classic text on this, as so often, is from Fredrik Lundh, the effbot. His advice: always use import - except when you shouldn't.

关于这个问题的经典文本,一如既往地,来自于弗德里克·伦德(Fredrik Lundh), effbot。他的建议是:永远使用进口——除非你不应该这么做。

In other words, be sensible. Personally I find that anything that's several modules deep tends to get imported via from x.y.z import a - the main example being Django models. But as much as anything else it's a matter of style, and you should have a consistent one - especially with modules like datetime, where both the module and the class it contains are called the same thing. Do you need to write datetime.datetime.now() or just datetime.now()? (In my code, always the former.)

换句话说,要明智。就我个人而言,我发现任何深入的模块都倾向于通过x.y导入。z导入a -主要示例是Django模型。但与其他任何东西一样,这是一个风格问题,您应该有一个一致的风格——特别是对于datetime这样的模块,它包含的模块和类都被称为相同的东西。您是否需要写入datetime.datetime.now()或datetime.now()?(在我的代码中,总是前者。)

Items 1 and 2 in your list of questions seem to be the same issue. Python's dynamic nature means it is fairly simple to replace an item in a module's namespace no matter which of the methods you use. The difficulty comes if one function in a module refers to another, which is the one you want to mock. In this case, importing the module rather than the functions means you can do module.function_to_replace = myreplacementfunc and everything works transparently - but that is as easy to do via FPIM as it is via IM.

在你的问题列表中,第1和第2项似乎是相同的问题。Python的动态特性意味着,无论使用哪种方法,替换模块名称空间中的项都相当简单。如果模块中的一个函数引用了另一个函数,那么就会出现问题,这就是您想要模拟的函数。在这种情况下,导入模块而不是函数意味着可以执行模块。function_to_replace = myreplacementfunc和所有的工作都是透明的——但是通过FPIM,这就像通过IM一样简单。

I also don't understand how item 3 has anything to do with anything. I think your item 4, however, is based on a bit of a misunderstanding. None of the methods you give will 'pollute your namespace'. What does do that is from module import *, where you have no idea at all what you're importing and so functions can appear in your code with no clue given to the reader where they came from. That's horrible, and should be avoided at all costs.

我也不明白第3项与任何事情有什么关系。我认为你的第4项,然而,是基于一点误解。您提供的任何方法都不会“污染您的名称空间”。它的作用是来自模块导入*,在那里你根本不知道你要导入什么,所以函数可以出现在你的代码中,却不知道它们来自哪里。这太可怕了,应该不惜一切代价避免。

#3


5  

Like Alex Martelli, I am fond of using as when importing a function.

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

One thing I have done is to use some prefix on all the functions that were imported from the same module:

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

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

r_seed is shorter to type than random.seed but somewhat preserves the module boundaries. Someone casually looking at your code can see r_seed() and r_random() and have a chance to grok that they are related.

r_seed的类型比random要短。种子但在某种程度上保留了模块边界。随意查看代码的人可以看到r_seed()和r_random(),并有机会摸索出它们是相关的。

Of course, you can always simply do:

当然,你可以简单地做到:

import random as r

and then use r.random() and r.seed(), which may be the ideal compromise for this case. I only use the prefix trick when I'm importing one or two functions from a module. When I want to use many functions from the same module, I'll import the module, perhaps with an as to shorten the name.

然后使用r.random()和r.seed(),这可能是理想的折衷方案。我只在从模块导入一两个函数时使用前缀技巧。当我想要在同一个模块中使用多个函数时,我将导入模块,可能使用一个来缩短名称。

#4


5  

Great answers here (I upvoted them all), and here are my thoughts on this matter:

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

First, addressing each of your bullets:

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

(Allegedly) Pros of FMIF:

(据说)FMIF的优点:

  • Shortness of code: shorter function names help stick to the 80 columns-per-line.
  • 代码简短:更短的函数名有助于每行保持80列。

Perhaps, but module names are usually short enough so this is not relevant. Sure, there's datetime, but also os, re, sys, etc. And Python has free line breaks inside { [ (. And for nested modules there's always as in both IM and FPIM

也许,但是模块名通常足够短,所以这是不相关的。当然,有datetime,也有os、re、sys等。Python在{[()中有空闲行。对于嵌套模块,IM和FPIM中都有

  • Readability: chisquare(...) appears more readable than scipy.stats.stats.chisquare(...).
  • 可读性:chisquare(…)看起来比scipy.stats.stats.chisquare(…)更具可读性。

Strongly disagree. When reading foreign code (or my own code after a few months) it's hard to know where each function comes from. Qualified names saves me from going back and forth from line 2345 to module declarations header. And it also gives you context: "chisquare? What's that? Oh, it's from scypy? Ok, some math-related stuff then". And, once again, you can always abbreviate scipy.stats.stats as scypyst. scypyst.chisquare(...) is short enough with all benefits of a qualified name.

强烈反对。当阅读外文代码(或几个月后我自己的代码)时,很难知道每个函数来自哪里。合格的名称使我不必在第2345行和模块声明头之间来回切换。它也给你上下文:“chisquare?”那是什么?从scypy哦,是吗?好的,一些数学相关的东西"同样,您也可以缩写scipy.stats。scypyst统计数据。chisquare(…)足够短,拥有一个合格名称的所有好处。

import os.path as osp is another good example, considering it's very common to chain 3 or more of its functions together in a single call: join(expanduser(),basename(splitext())) etc.

进口操作系统。path作为osp是另一个很好的例子,考虑到将3或更多的函数链接在一个调用中是很常见的:join(expanduser()、basename(splitext()))等。

  • Ease of redirection: one-line redefinition of a function from altmodule instead of module.
  • 易于重定向:从altmodule而不是模块重新定义函数的一行代码。

How often you want to redefine a single function but not whole module? Module boundaries and function coordination should be preserved, and Alex already explained this in great depth. For most (all?) real-world scenarios, if alt_module.x is a viable replacement for module.x, then probably alt_module itself is a drop in alternative for module, so both IM and FPIM are one-liners just like FMIF, provided you use as.

您希望重新定义单个函数而不是整个模块的频率是多少?模块边界和功能协调需要保留,Alex已经对此做了深入的说明。对于大多数真实场景(全部?),如果是alt_module。x是一个可行的模块替代品。所以IM和FPIM都是一行程序,就像FMIF一样,只要您使用as。

  • I realize FPIM goes some way to nullifying the first two issues...
  • 我意识到FPIM在某种程度上取消了前两个问题……

Actually, as is the one that mitigates the first 2 issues (and the 3rd), not FPIM. You can use IM for that too: import some.long.package.path.x as x for the same result as FPIM.

实际上,缓解前两个问题(和第三个问题)的是FPIM,而不是FPIM。你也可以用IM: import some.long.pack .path。x = x = FPIM。


So none of the above are really pros of FMIF. And the reasons I prefer IM/FPIM are:

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

For the sake of simplicity and consistency, when I import something, either IM or FPIM, I'm always importing a module, not an object from a module. Remember FMIF can be (ab-)used to import functions, classes, variables, or even other modules! Think about the mess of from somemodule import sys, somevar, os, SomeClass, datetime, someFunc.

为了简单和一致,当我导入一些东西时,无论是IM还是FPIM,我总是从模块中导入一个模块,而不是对象。记住,FMIF可以(ab-)用于导入函数、类、变量,甚至其他模块!想想那些从somemodule导入系统、somevar、os、SomeClass、datetime、someFunc中产生的混乱。

Also, if you want more than a single object from a module, FMIF will pollute your namespace more than IM or FPIM, which will use a single name no matter how many objects you want to use. And such objects will have a qualified name, which is a pro, not a con: as I've said in issue 2, IMHO a it improves readability.

此外,如果您想从模块中获得多个对象,那么FMIF会比IM或FPIM更容易污染您的命名空间,无论您想要使用多少对象,FMIF都会使用一个名称。这样的对象将有一个限定的名称,这是一个专业名称,而不是一个缺点:正如我在第2期中所说,IMHO a将提高可读性。

it all comes down to consistency, simplicity, organization. "Import modules, not objects" is a good, easy mind model to stick with.

这一切都归结于一致性、简单性和组织性。“导入模块,而不是对象”是一个很好的、容易坚持的思想模型。

#5


1  

I agree with MestreLion the most here (and so an upvote).

我最同意MestreLion的观点(所以我投了赞成票)。

My perspective: I review code frequently that I am unfamiliar with, and not knowing what module a function is coming from just looking at the function is quite frustrating.

我的观点是:我经常检查我不熟悉的代码,不知道一个函数的模块来自于什么函数,这让我很沮丧。

Code is written once and read many times, and so readability and maintainability trumps ease of typing.

代码一次编写,多次读取,因此可读性和可维护性胜过易于输入。

In a similar vein, typically code is not being written for the benefit of the coder, but for the benefit of another entity.

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

Your code should be readable to someone who knows python better than you, but is unfamiliar with the code.

对于比您更了解python但不熟悉代码的人来说,您的代码应该是可读的。

Full path imports can also better help IDE's point you at the correct source of the function or object you're looking at.

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

For all of these reasons and the reasons MestreLion noted, I conclude that it is best practice to import and use the full path.

由于所有这些原因和MestreLion指出的原因,我认为导入和使用完整路径是最佳实践。