如何确定julia脚本是作为模块包含还是作为脚本运行?

时间:2018-03-20 23:35:29

标签: julia

我想知道如何用Julia语言确定file.jl是否作为脚本运行,例如在调用中:

bash$ julia file.jl

例如,只有在这种情况下才能启动函数main。因此,我可以使用include('file.jl'),而无需实际执行该函数。

具体来说,我正在寻找类似已回答的问题in a python question

def main():
    # does something

if __name__ == '__main__':
    main()

编辑: 更具体地说,在非交互式(例如脚本)环境中使用Base.isinteractive时,方法include('file.jl')(请参阅here)无法解决问题。

2 个答案:

答案 0 :(得分:3)

全局常量PROGRAM_FILE包含从命令行传递给Julia的脚本名称(调用include时不会更改)。

另一方面,@__FILE__宏为您提供了文件的名称。

例如,如果你有一个文件:

a.jl

println(PROGRAM_FILE)
println(@__FILE__)
include("b.jl")

b.jl

println(PROGRAM_FILE)
println(@__FILE__)

您有以下行为:

$ julia a.jl
a.jl
D:\a.jl
a.jl
D:\b.jl

$ julia b.jl
b.jl
D:\b.jl

总结:

  • PROGRAM_FILE告诉您Julia开始使用的文件名是什么;
  • @__FILE__告诉您实际调用宏的文件。

答案 1 :(得分:2)

tl; dr版本:

if !isdefined(:__init__) || Base.function_module(__init__) != MyModule
  main()
end

<强>解释

似乎有些混乱。 Python和Julia在“模块”方面的工作方式截然不同(尽管两者使用相同的术语,原则上它们是不同的)。

在python中,源文件是模块或脚本,具体取决于您选择“加载”/“运行”它的方式:存在样板,用于检测运行源代码的环境,方法是查询执行时嵌入模块的__name__。例如。如果您有一个名为mymodule.py的文件,则将其正常导入,然后在模块定义中,变量__name__自动设置为值mymodule;但如果您将其作为独立脚本运行(有效地将代码“转储”到“main”模块中),__name__变量就是全局范围的变量,即__main__。这种差异使您能够检测如何运行python文件,因此在每种情况下您的行为都会略有不同,这正是样板文件的作用。

然而,在julia中,模块被明确定义为代码。无论您是module还是using,运行包含include声明的文件都会加载该模块;但是在前一种情况下,如果模块已经在工作区中,则不会重新加载模块,而在后一种情况下,就好像你“重新定义”它一样。

模块可以通过特殊的__init__()函数获得初始化代码,该函数的作用是仅在第一次加载模块时运行(例如,通过using语句导入时)。所以你可以做的一件事是拥有一个独立的脚本,你可以include直接作为一个独立的脚本运行,或includemodule定义的范围内,并且它检测模块特定变量的存在,使其在每种情况下表现不同。但它仍然必须是一个独立的文件,与主模块定义分开。

如果您希望模块执行某些操作,那么独立脚本不应该这样做,这很简单:您只需要这样的内容:

module MyModule
  __init__() = # do module specific initialisation stuff here
  include("MyModule_Implementation.jl")
end

如果您想要相反的情况,您需要一种方法来检测您是否在模块内运行。你可以这样做,例如通过检测属于该特定模块的合适__init__()函数的存在。例如:

### in file "MyModule.jl"
module MyModule
  export fun1, fun2;
  __init__() = print("Initialising module ...");
  include("MyModuleImplementation.jl");
end

### in file "MyModuleImplementation.jl"
fun1(a,b) = a + b;
fun2(a,b) = a * b;

main() = print("Demo of fun1 and fun2.     \n" *
               "  fun1(1,2) = $(fun1(1,2)) \n" *
               "  fun2(1,2) = $(fun2(1,2)) \n");

if !isdefined(:__init__) || Base.function_module(__init__) != MyModule
  main()
end

如果MyModule作为模块加载,则main中的MyModuleImplementation.jl功能将无法运行。

如果您将MyModuleImplementation.jl作为独立脚本运行,则main函数将运行。

所以这是一种达到你想要的效果的方法;但是将模块定义文件作为模块或独立脚本运行是非常不同的;我不认为你可以简单地从代码中“剥离”module指令,并以这种方式在julia中运行模块的“内容”。