加载代码的require和import方法有哪些优缺点?

问题描述:

Ruby使用require,Python使用import。他们是完全不同的模型,虽然我更习惯require模型,但我可以看到一些地方,我认为我更喜欢import。我很好奇人们发现哪些东西特别容易 - 或者更有趣,比他们应该更难 - 与这些模型中的每一个。加载代码的require和import方法有哪些优缺点?

特别是,如果您正在编写新的编程语言,您将如何设计代码加载机制?哪些“优点”和“缺点”会对您的设计选择造成重大影响?

+2

为什么这应该是一个社区wiki?这是一个明确的,可回答的问题! – Dario 2009-12-04 20:34:20

+0

因为我在问一个问题,答案可能是主观的。人们肯定有一种个人偏好的方式。我对主观偏好感兴趣,如果他们背后有一个合理的理由,超越“我更喜欢这个”。 – 2009-12-04 20:42:43

+0

我很想知道问题的背景,你会根据导入还是要求选择另一种语言? – 2009-12-08 19:58:03

Python的import有一大特点,它捆绑了两两件事一起 - 如何找到进口什么命名空间包含它

这将创建非常明确的代码:

import xml.sax

这指定在哪里找到我们想要由Python搜索路径的规则来使用,代码。

与此同时,我们要访问的所有对象都位于此确切名称空间下,例如xml.sax.ContentHandler

我认为这是Ruby需求的一个优势。 require 'xml'实际上可能会使命名空间XML或模块中可用的任何其他命名空间内的对象,而不需要直接从require行显示。

如果xml.sax.ContentHandler太长,你可能会在导入时指定一个不同的名称:

import xml.sax as X 

而且现在X.ContentHandler下是avalable。

这样Python需要你明确地构建每个模块的命名空间。 Python的命名空间是因此非常“物理”,我会解释我的意思:

  • 默认情况下,只有在模块中直接定义的名称在其命名空间中可用:函数,类等等。
  • 要添加到模块的名称空间,您明确地导入了您希望添加的名称,将它们(通过引用)“物理地”放置在当前模块中。

例如,如果我们有小Python包“过程”与内部子模块machineinterface,我们希望市直包名,代表这个作为一个方便的命名空间,这是和例子我们所能在“包定义”文件process/__init__.py写:

from process.interface import * 
from process.machine import Machine, HelperMachine 

因此我们举起一个通常来说是可访问的process.machine.Machine高达process.Machine。我们以非常明确的方式将所有名称从process.interface添加到process名称空间。

Python的进口,我写的好处是简单地二:

  • 清除你有什么用import
  • 明确时,你如何修改自己的模块的命名空间(程序或为其他人导入)
+0

我同意这是一个很好用的功能,但是我发现有一些像'__init __。py'这样的学习曲线更加陡峭,如果由于某种原因你没有灵活的目录结构,这会使命名空间完全相同你想要的方式有点困难。 – 2009-12-04 20:39:43

+0

我想知道为什么你没有“灵活的目录结构”? – 2009-12-09 01:45:12

+0

@Bob:当然,这是缺点。我看到它的方式,您提到的优势@ kaizer.se的交易学习曲线更陡。如果你问我,这是值得的。 – 2009-12-09 01:57:14

免责声明,我绝不是Python专家。

我看到require超过import的最大优点就是您不必担心理解名称空间和文件路径之间的映射。很明显:这只是一个标准的文件路径。

我真的很喜欢import所具有的命名空间的重点,但不禁要问,这种特殊的方法是不是太不灵活。据我所知,在Python中控制模块命名的唯一方法是更改​​正在导入的模块的文件名或使用重命名。此外,使用明确的命名空间,您可以通过其完全限定的标识符来引用某些东西,但是使用隐式命名空间,您无法在模块本身内部执行此操作,并且这可能会导致潜在的歧义没有重命名很难解决。

foo.py

class Bar: 
    def myself(self): 
    return foo.Bar 

这种失败:

 
Traceback (most recent call last): 
    File "", line 1, in ? 
    File "foo.py", line 3, in myself 
    return foo.Bar 
NameError: global name 'foo' is not defined 

两种实现使用的位置列表,从搜索,这在我看来是一个极为重要的组成部分,无论你选择的模型。

如果使用像require这样的代码加载机制,但该语言根本没有全局名称空间会怎么样?即任何地方都必须有名称空间,但开发人员完全可以控制定义类的哪个名称空间,并且该名称空间声明在代码中显式地发生,而不是通过文件名。或者,在全局名称空间中定义一些内容会生成警告。这是一种两全其美的方法,还是我缺少一个明显的缺点?

+0

其实你可以返回'foo.Bar',如果你在'我自己'的方法中'import foo'就在它的上面。但是,当你可以返回'Bar'时,你为什么要这么做? – 2009-12-09 00:36:42

+1

在这个例子中,显然,是的,返回Bar正是你想要做的。但是,我正在编写一些代码,其中有些代码是由其他作者编写的插件。我需要特别小心不明确的命名空间。幸运的是,我刚刚从__future__ import absolute_import中发现了'',这几乎完全缓解了这个问题。 – 2009-12-09 01:47:33

+1

为什么不把你的插件放在你的应用程序的目录中,比如'插件',每个插件都有自己的子目录?这样,插件之间就不会有冲突,你可以__import__而不用做黑魔法,并用__subclasses__找到实现。如果插件作者像'导入字符串'那样执行冲突导入,那不是你的问题,或者如果是的话,他们不再是真正的插件;) – 2009-12-09 02:20:36

require的一个不错的属性是它实际上是一个在Kernel中定义的方法。因此,您可以覆盖它并实现您自己的Ruby包装系统,这是例如Rubygems呢!

PS:我不是在这里卖猴子补丁,而是Ruby的包系统可以被用户重写(甚至像python系统一样工作)。当你编写一门新的编程语言时,你不能把所有的东西都弄对。因此,如果您的导入机制可以从语言内部完全扩展(完全指向所有方向),那么您将为未来的用户提供最好的服务。从自身内部不完全扩展的语言是进化的死胡同。我会说这是Matz与Ruby合作的原因之一。

+0

我不会-1这个,但在Ruby中存在的猴子修补是有问题的,而不是我想鼓励的东西。一个好的包装系统可以简单地修改搜索路径并保留单独的代码加载。 – 2009-12-09 00:24:14

+0

嗯...我相当确定你不能在Ruby中模拟Python的导入系统。你可能会得到一些与之相似的东西,但这可能是一种彻头彻尾的破解,它可能破坏各种代码,如果你在生产环境中使用它,你会让很多人失望。 – 2009-12-09 06:11:15

+0

-1因为声称不卖猴子补丁而卖猴子补丁。同时也是对Python的导入机制一无所知(无论如何也愿意苛刻)。我见过的第一个答案是,如果可以的话,我会不止一次地倒退。 – 2009-12-13 07:30:16

Python的导入提供了一种非常明确的命名空间:命名空间是路径,您不必查看文件就可以知道它们在哪些命名空间中进行定义,并且文件不会与命名空间定义混杂在一起。这使得应用程序的命名空间方案简单且快速理解(仅查看源代码树),并避免了像名称空间声明一样的简单错误。

一个不错的副作用是每个文件都有它自己的私有名称空间,所以在命名事物时不必担心冲突。

有时命名空间也会变得烦人,像some.module.far.far.away.TheClass()这样的东西在任何地方都可能很快让你的代码变得非常长而且无聊。在这些情况下,您可以使用import ... from ...并在当前一个注入另一个名称空间的位。如果注入导致与要导入的模块冲突,则可以简单地重命名您导入的内容:from some.other.module import Bar as BarFromOtherModule

Python仍然很容易出现像循环导入这样的问题,但它的应用程序设计不仅仅是在这些情况下必须指责的语言。

因此,python采取了C++ namespace#include并在很大程度上延伸它。另一方面,我没有看到ruby的modulerequire以何种方式为这些添加了新的东西,并且您有像全局命名空间混乱一样的可怕问题。

+0

Ruby的要求在语言中是完全可扩展的。如果你不喜欢它的导入语义,你可以去改变它们!这不能用C++或python来完成,所以至少在这方面,Ruby会为导入作品的方式增加一些重大新闻。 – akuhn 2009-12-09 02:03:16

+4

您可以像在Ruby中一样自定义python导入机制。但在这两种情况下,这听起来像一个非常糟糕的主意。当两个第三方模块定制导入机制时会发生什么?这种事情必须是标准的,而对于我来说,红宝石的标准机制是不够的。 – 2009-12-09 02:25:36