两个模块,都导出相同的名称

时间:2016-09-18 05:57:05

标签: module packages julia

我想要使用两个包:CorpusLoaders.jlWordNet.jl

  • CorpusLoaders.SemCor导出sensekey(::SenseTaggedWord)
  • WordNet导出sensekey(::DB, ::Synset, ::Lemma)

我想使用两种sensekey方法。

例如

对于某些混合的项目列表:mixedlist::Vector{Union{Tuple{SenseTaggedWord},Tuple{DB, Synset,Lemma}}。 即列表中的项目是1个元组SenseTaggedWord和3个DBSynsetLemma元组的混合。

for item in mixedlist
    println(sensekey(item...)
end

应该有效。 这个例子有点滑稽,因为我为什么要像这样混合它们。 但是,希望它有助于说明一般情况下的问题。

尝试using CorpusLoaders.SemCor, WordNet将结果导入WARNING: both WordNet and Semcor export "sensekey"; uses of it in module Main must be qualified.

手动导入两个:import CorpusLoaders.SemCor.sensekey; import WordNet.sensekey会导致WARNING: ignoring conflicting import of Semcor.sensekey into Main

可以做些什么?我想要他们两个,由于多次发送,他们并没有真正发生冲突。

鉴于CorpusLoaders.jl是我正在编写的包,我还有一些选项,因为我可以使我的CorpusLoaders.jl依赖于WordNet.jl。 如果我确实做了,那么我可以在CorpusLoaders.jl

中说
 import WordNet
 function WordNet.sensekey(s::SenseTaggedWord)...

这将使他们都工作。 但这意味着要求WordNet作为CorpusLoaders的依赖。

我想知道如何为包的消费者解决问题 - 而不是作为包的创建者。

3 个答案:

答案 0 :(得分:6)

在这种情况下,功能不会发生冲突,但通常无法保证。可能是稍后加载的包将向其中一个将发生冲突的函数添加方法的情况。因此,为了能够对这两个包使用sensekey,需要一些额外的保证和限制。

执行此操作的一种方法是忽略两个包sensekey,而是提供您自己的,调度到正确的包:

sensekey(x) = CorpusLoaders.sensekey(x)
sensekey(x, y, z) = WordNet.sensekey(x,y,z)

答案 1 :(得分:6)

tl; dr 通过其模块名称空间在脚本中使用这些函数时对这些函数进行限定,即CorpusLoader.sensekey()WordNet.sensekey()

解释

编辑后我对你的问题的理解(谢谢你澄清)是:

  • 您编写了一个名为CorpusLoaders.jl的程序包,该程序包导出函数sensekey(::SenseTaggedWord)
  • 有一个名为WordNet.jl的外部包,它导出函数sensekey(::DB, ::Synset, ::Lemma)
  • 您有一个使用这两个模块的脚本。

你担心using模块或"导入"这些函数可能直接在脚本中产生歧义和/或错误,并要求

  1. 如何编写我的CorpusLoaders包以防止与其他包发生冲突,
  2. 如何编写我的脚本以明确消除两个功能之间的歧义,同时仍然允许使用它们?
  3. 我认为这源于一种轻微的混淆,usingimport彼此不同,以及模块如何创建命名空间。这在文档here中得到了很好的解释。

    实质上,答案是:

    1. 您不必担心从您的模块中导出会与其他模块冲突的东西。这就是模块的用途:您正在创建一个命名空间,这将有资格获得"所有导出的变量,例如CorpusLoaders.sensekey(::SenseTaggedWord)

    2. 当您输入using CorpusLoaders时,您对julia所说的是&#34;导入模块本身,从其命名空间中删除的所有导出变量限定符,并将它们带入Main&#34;。请注意,这意味着您现在可以直接从Main访问sensekey而不使用名称空间限定符作为CorpusLoaders.sensekey(),因为您还导入了< em> module 作为您可以使用的变量。

    3. 如果您再尝试using模块WordNet,julia会非常合理地发出警告,主要是说:

        

      &#34;您已经导入了两个具有相同名称的功能。我不能只删除它们的命名空间,因为这可能会在某些情况下产生问题(即使在你的情况下它也不会因为它们有不同的签名,但我通常不可能知道这一点) 。如果要使用这些函数中的任何一个,请使用适当的命名空间限定符&#34;。

      所以,2的解决方案是:

      • 你要么

        using CorpusLoaders;
        using WordNet;
        

        ,忽略警告,在主命名空间中照常导入所有其他导出的变量,并在每次需要使用它们时通过CorpusLoaders.sensekey()WordNet.sensekey()模块直接访问这些特定函数你的脚本,或

      • 通过执行

        ,您可以始终清楚地消除两个模块的歧义
        import CorpusLoaders;
        import WordNet;
        

        并适当地限定所有变量,或

      • 在这种特殊情况下功能签名不会发生冲突,如果你真的喜欢能够在没有命名空间限定符的情况下使用该功能,依赖于相反,你可以做一些类似凤阳建议的事情:

         import CorpusLoaders;
         import WordNet;
         sensekey(a::SenseTaggedWord) = CorpusLoader.sensekey(a);
         sensekey(a::DB, b::Synset, c::Lemma) = WordNet.sensekey(a, b, c);
        

        本质上是一个 new 函数,在模块Main上定义,充当两个名称空间限定函数的包装器。

      最后,所有这些都归结为使用using vs import和命名空间适合您的特定代码。 :)

      <小时/> 作为附录,使用CorpusLoaderWordNet之类的长命名空间限定符可能会使代码变得非常难以处理。 julia没有类似python的import numpy as np之类的东西,同时模块成为你工作区的简单变量,所以创建一个简单的变量是微不足道的。他们的别名。所以你可以这样做:

      import CorpusLoaders; const cl = CorpusLoaders;
      import Wordnet;       const wn = WordNet;
      # ... code using both cl.sensekey() and wn.sensekey()
      

答案 2 :(得分:5)

我实施了@Fengyang Wang所说的, 作为一个功能:

function importfrom(moduleinstance::Module, functionname::Symbol, argtypes::Tuple)
    meths = methods(moduleinstance.(functionname), argtypes)
    importfrom(moduleinstance, functionname, meths)
end 

function importfrom(moduleinstance::Module, functionname::Symbol)
    meths = methods(moduleinstance.(functionname))
    importfrom(moduleinstance, functionname, meths)
end 

function importfrom(moduleinstance::Module, functionname::Symbol, meths::Base.MethodList)
    for mt in meths
        paramnames = collect(mt.lambda_template.slotnames[2:end])
        paramtypes = collect(mt.sig.parameters[2:end])
        paramsig = ((n,t)->Expr(:(::),n,t)).(paramnames, paramtypes)

        funcdec = Expr(:(=), 
                        Expr(:call, functionname, paramsig...),
                        Expr(:call, :($moduleinstance.$functionname), paramnames...)
        )
        current_module().eval(funcdec) #Runs at global scope, from calling module

    end
end

致电:

using WordNet
using CorpusLoaders.Semcor

importfrom(CorpusLoaders.Semcor, :sensekey)
importfrom(WordNet, :sensekey)

methods(sensekey)

通用功能sensekey的2种方法:

  • sensekey(db :: WordNet.DB,ss :: WordNet.Synset,lem :: WordNet.Lemma)
  • sensekey(saword :: CorpusLoaders.Semcor.SenseAnnotatedWord

如果你想获得真正的闪存,你也可以重新出口DocString。