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

Module 两个模块,都导出相同的名称,module,packages,julia,Module,Packages,Julia,我想使用两个包:,和 微粒装载机.SemCor导出sensekey(::SenseTaggedWord) WordNet导出sensekey(::DB,::Synset,::Lemma) 我想使用这两种sensekey方法 乙二醇 对于一些混合项列表:mixedlist::Vector{Union{Tuple{SenseTaggedWord},Tuple{DB,Synset,Lemma}。 即列表中的项目由1个元组的sensetagedword和3个元组的DB、Synset和Lemma组成

我想使用两个包:,和

  • 微粒装载机.SemCor导出
    sensekey(::SenseTaggedWord)
  • WordNet导出sensekey(::DB,::Synset,::Lemma)
我想使用这两种
sensekey
方法

乙二醇

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

for item in mixedlist
    println(sensekey(item...)
end
应该有用。 这个例子有点滑稽,因为我为什么要这样混合它们。 但是,希望它能说明一般情况下的问题

试图
使用CorpusLoaders.SemCor、WordNet
警告中引入这两个结果:WordNet和SemCor都导出“sensekey”;在模块Main中使用它必须是合格的。

手动导入这两者:
import-CorpusLoaders.SemCor.sensekey;import-WordNet.sensekey
将导致
警告:忽略将SemCor.sensekey导入Main的冲突

可以做什么?我想要两者,而且它们不会因为多次调度而发生冲突。


鉴于CorpusLoaders.jl是我正在编写的一个包,我还有一些选择,因为我可以让我的CorpusLoaders.jl依赖于WordNet.jl。 如果我做了,那么我可以在CorpusLoaders.jl中说

 import WordNet
 function WordNet.sensekey(s::SenseTaggedWord)...
这将使它们都起作用。 但这意味着需要WordNet作为微粒装载机的依赖项

我想知道如何为软件包的消费者解决这个问题,而不是作为软件包的创建者


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

一种方法是忽略两个包的
sensekey
,而是提供您自己的,发送到正确的包:

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

我实现了@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的两种方法:

  • sensekey(db::WordNet.db,ss::WordNet.Synset,lem::WordNet.Lemma)
  • sensekey(saword::微粒装载机.Semcor.SenseAnnotatedWord)

如果你想得到真正的flash,你也可以重新导出DocString。

tl;dr在脚本中使用函数时,通过它们的模块名称空间,即
CorpusLoader.sensekey()
WordNet.sensekey()


解释

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

  • 您已经编写了一个名为
    CorpusLoaders.jl
    的包,它导出函数
    sensekey(::SenseTaggedWord)
  • 有一个名为
    WordNet.jl
    的外部包,它导出函数
    sensekey(::DB,::Synset,::Lemma)
  • 您有一个使用这两个模块的脚本
您担心
使用模块或直接“导入”函数可能会在脚本中产生歧义和/或错误

  • 如何编写我的
    CorpusLoaders
    包以防止与其他包发生潜在冲突,以及
  • 我如何编写脚本来清楚地消除这两个函数之间的歧义,同时仍然允许使用它们
  • 我认为这源于对
    使用
    导入
    之间的区别,以及模块如何创建名称空间的轻微混淆。这在文档中有很好的解释

    基本上,答案是:

  • 您不必担心从模块中导出会与其他模块冲突的内容。这就是模块的用途:您正在创建一个名称空间,该名称空间将“限定”所有导出的变量,例如
    CorpusLoaders.sensekey(::SenseTaggedWord)

  • 当您使用微粒加载器键入
    时,您要对julia说的是“导入模块本身,以及从名称空间限定符中剥离出来的所有导出变量,并将它们带到Main中”。请注意,这意味着您现在可以直接从Main以函数的形式访问
    sensekey
    ,而无需名称空间限定符,也可以作为
    CorpusLoaders.sensekey()
    ,因为您还将模块作为可使用的变量导入

  • 如果您随后尝试使用
    模块
    WordNet
    ,julia会非常合理地发出警告,其实质是:

    “您导入了两个同名的函数。我不能只删除它们的命名空间,因为这可能会在某些情况下产生问题(即使在您的情况下不会,因为它们具有不同的签名,但我一般不可能知道这一点)。如果要使用这些函数中的任何一个,请使用其相应的命名空间限定符”

    因此,2.的解决方案是:

    • 你也可以

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

    • 通过这样做,您可以始终清楚地消除两个模块之间的歧义

      import CorpusLoaders;
      import WordNet;
      
      并适当地限定所有变量,或

    • 在函数签名不冲突的特定情况下,如果您真的希望能够在不使用名称空间限定符的情况下使用函数,而是依赖于多个分派,那么您可以执行类似FengYang建议的操作:

       import CorpusLoaders;
       import WordNet;
       sensekey(a::SenseTaggedWord) = CorpusLoader.sensekey(a);
       sensekey(a::DB, b::Synset, c::Lemma) = WordNet.sensekey(a, b, c);
      
      这本质上是一个import CorpusLoaders; const cl = CorpusLoaders; import Wordnet; const wn = WordNet; # ... code using both cl.sensekey() and wn.sensekey()