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

Lyn*_*ite 3 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,的AND3元组DB,SynsetLemma.

for item in mixedlist
    println(sensekey(item...)
end
Run Code Online (Sandbox Code Playgroud)

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

试图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)...
Run Code Online (Sandbox Code Playgroud)

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

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

Tas*_*nou 7

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


说明

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

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

并且您担心using模块或直接"导入"函数可能会在脚本中产生歧义和/或错误

  1. 如何编写我的CorpusLoaders包以防止与其他包的潜在冲突,以及
  2. 如何编写我的脚本以清楚地消除这两个功能之间的歧义,同时仍允许它们使用?

我认为这源于一种轻微的混淆using,import它们之间是如何相互不同的,以及模块如何创建命名空间.这里的文档非常好地解释了这一点.

从本质上讲,答案是:

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

  2. 当你输入时using CorpusLoaders,你对julia说的是"导入模块本身,从命名空间限定符中删除所有导出的变量,并将它们带入Main".请注意,这意味着您现在可以访问sensekey直接从主函数没有命名空间限定,作为CorpusLoaders.sensekey(),因为你还进口的模块,你可以使用一个变量.

如果你然后尝试using模块WordNet,julia非常合理地发出警告,基本上说:

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

那么,2的解决方案是:

  • 你要么做

    using CorpusLoaders;
    using WordNet;
    
    Run Code Online (Sandbox Code Playgroud)

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

  • 通过这样做,你可以随时清楚地消除两个模块的歧义

    import CorpusLoaders;
    import WordNet;
    
    Run Code Online (Sandbox Code Playgroud)

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

  • 在这个函数签名没有冲突的特殊情况下,如果你真的希望能够使用没有命名空间限定符的函数,而是依赖于多个调度,你可以做一些像FengYang所建议的:

     import CorpusLoaders;
     import WordNet;
     sensekey(a::SenseTaggedWord) = CorpusLoader.sensekey(a);
     sensekey(a::DB, b::Synset, c::Lemma) = WordNet.sensekey(a, b, c);
    
    Run Code Online (Sandbox Code Playgroud)

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

最后,这一切都归结为为您的特定代码适当地使用usingvs import和名称空间.:)


作为附录,代码可能会变得非常难以使用像CorpusLoader和那样的长命名空间限定符WordNet.julia没有类似python的东西import numpy as np,同时模块成为工作区的简单变量,因此为它们创建别名是微不足道的.所以你可以这样做:

import CorpusLoaders; const cl = CorpusLoaders;
import Wordnet;       const wn = WordNet;
# ... code using both cl.sensekey() and wn.sensekey()
Run Code Online (Sandbox Code Playgroud)


Fen*_*ang 6

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

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

sensekey(x) = CorpusLoaders.sensekey(x)
sensekey(x, y, z) = WordNet.sensekey(x,y,z)
Run Code Online (Sandbox Code Playgroud)


Lyn*_*ite 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
Run Code Online (Sandbox Code Playgroud)

致电:

using WordNet
using CorpusLoaders.Semcor

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

methods(sensekey)
Run Code Online (Sandbox Code Playgroud)

通用功能sensekey的2种方法:

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

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