Python与Julia结合使用的个人经验


本人非专业程序员,下面讲的是我从事科学计算时得到的一点心得。
Julia速度很快,我随手写的Julia代码,常常比我精心用numba优化的Python代码快。但另一方面,Python确实令我难以割舍。一是Julia绘图国内教程较少,我看官方文档也画不出满意的图;二是Python的库确实很多,上至很多专业软件都出了相应的Python库,下至我们组内也流传着师兄写的伪彩图函数。
因此我还是希望Python继续发挥“胶水”的作用,来整合 自己写的Julia包以及其他程序结果。

一、库的创建

1.1. Python库的创建

暂略。搜__init__.py的用法。

1.2. Julia包的创建

关于包的创建,暂且先参考这个视频
下次我再创建包的时候,可以来记录下我的简单流程。

第一步,我们需要Julia REPL,目录为你要放置包的目录。
比如我的包都放在

"D:\\Documents\\Julia\\MyModules"

中,我是windows平台,在这里shift+右键,选择“在此处打开Powershell窗口”,然后输入Julia启动REPL。这时默认就是上面的文件夹:

julia> pwd()
"D:\\Documents\\Julia\\MyModules"

(其实VSCode下面的窗口也可以)

第二步,按下]切换到包管理模式——我们要创建包,所以后面都是在包管理模式下。输入generate 包名。于是,在你当前文件夹下面会出现两个文件:

(@v1.6) pkg> generate 包名
  Generating  project 包名:
    包名\Project.toml
    包名\src/包名.jl

这里:

  • 包名一整个文件夹就是你的包;
    • 包目录下面src文件夹是代码文件存放处;
      • src下面的包名.jl则是和包同名的源文件。包的主体:module...end模块、using了哪些别人的包、export了哪些函数,就在这里。如果你有很多文件,可以用include("./XXX.jl")来包含。
    • 包目录下面Project.toml是程序员能看懂的环境管理信息。你的包如果调用别的包,在这里就能看到所依赖的版本。

第三步,切换到包目录,即Project.toml所在的目录。然后利用Project.toml的内容:

(@v1.6) pkg> activate .
  Activating environment at `D:\Documents\Julia\MyModules\包名\Project.toml`
  
 (包名) pkg>

激活当前文件夹所在的环境。注意pkg>前面会变成你的包名。

第四步

(包名) pkg> instantiate
  No Changes to `D:\Documents\Julia\MyModules\包名\Project.toml`
  No Changes to `D:\Documents\Julia\MyModules\包名\Manifest.toml`

很明显,初始化一些东西。此时会额外在跟目录下生成Manifest.toml文件。它是机器看得懂的Project.toml。听说如果你调用别人的库,可以锁代码版本,我不会。后面你添加了别人的包,这里也会更新。这个貌似后面要经常更新。

第五步(其实可以穿插在编辑源码的过程中),添加一些包,

(包名) pkg> add 其它包名

二、库的调用

2.1. Julia调用Julia包

假设你已经创建了自己的程序库/包,可以研究下这段代码:

try
	global computername = ENV["COMPUTERNAME"]     # windows电脑只有"COMPUTERNAME"
catch
	global computername = ENV["HOSTNAME"]    # Linux只有"HOSTNAME"
end

if computername == "家里电脑"
	push!(LOAD_PATH, "E:/Documents/JuliaProgram/MyModules/")    # 只有一个平台的看这一行就好
elseif computername == "宿舍电脑"
	push!(LOAD_PATH, "F:/Documents/JuliaProgramme/MyModules")
elseif computername=="DESKTOP-FDIN0I7"
	push!(LOAD_PATH, "D:/Documents/Julia/MyModules")
end

上面之所以要global是因为Julia中文文档-变量作用域中有写,try...catch...end会引入局部的作用域(局部作用域是一个易错点):

  • 若之前computername已经定义,它会出现歧义警告,并在try内创建局部变量(注意:交互和非交互结果不同);
  • 若之前computername未定义,则只会在try内创建局部变量,用完就丢掉。为了防止变成全局变量,需要加上global来提示。

这段代码,总的来说实现了两个功能:

  1. 将你自己的包目录添加到搜索目录;
  2. 不同电脑/服务器可以运行同样的代码。第一行是为了获得电脑名;后面是为了针对不同的电脑/服务器(不同电脑可以用onedrive、坚果云、群晖等等同步同一个个人程序库),分别将你的包目录添加到LOAD_PATH,这样你using或者import的时候,Julia就会分情况添加你的库。

2.2. Python中调用Python库

import socket, sys
host_name = socket.gethostname()
if (host_name == 'localhost.localdomain'): sys.path.insert(0, '/home/XXX/MyFunction') # 导师工作站
if (host_name[0:6] == 'acc-ap'): sys.path.insert(0, '/sharefs/heps/user/XXX/MyFunction') # acc-apXX服务器
if (host_name == 'DESKTOP-FDIN0I7'): sys.path.insert(0, 'D:/Documents/PythonFiles/001.科研/000.Accelerator/MyFunctionForAccelerator') # 办公室电脑
if (host_name == '宿舍电脑'): sys.path.insert(0, r'F:/Documents/PythonProgramme/001.科研/000.Accelerator/MyFunctionForAccelerator') # 宿舍电脑
if (host_name == 'XXXXX'): sys.path.insert(0, r'D:/PythonFile/001.科研/000.Accelerator/MyFunctionForAccelerator') # Surface
if (host_name == '家里电脑'): sys.path.insert(0, r'E:/Documents/PythonProgramme/001.科研/000.Accelerator/MyFunctionForAccelerator') # 家里电脑

前两段是为了获得电脑/服务器名,剩下就是为了针对不同电脑,将各自的库文件夹添加到Python搜索的目录。

2.3. Julia调用Python库

需要安装PyCall这个Julia包。
请注意下面py前缀,这个在Julia中称为“宏”,类似Python中的“装饰器”。我的理解,它的作用就是:

  1. 打开python内核(如果这段程序前面没有打开的话);
  2. 提交后面紧接的文字给python内核——有点像你在python终端中打字给它;
  3. 等着新的指令——意味着后面可以接着前面继续执行。
using PyCall

py"""
import matplotlib.pyplot as plt
plt.style.use("science")
"""

xdata = [0.0, 1, 2, 3, 4]
ydata = [4.0, 3, 2, 1, 0]

py"""
def plot1(xdata, ydata, xlabel, ylabel):
    plt.figure(figsize=(3,3), dpi=200)
    plt.plot(xdata, ydata)
    plt.grid()
    plt.xlabel(xlabel)
    plt.ylabel(ylabel)
    plt.show()
"""

py"plot1"(xdata, ydata, raw"$x$", raw"$y_1$") # 这里有传参的方法

可以看到我三次分别提交的py装饰的python程序片段,它都能正确执行。
在这里插入图片描述

2.4. Python中调用Julia包

首先在python中安装Julia库。

> pip install Julia -i https://pypi.tuna.tsinghua.edu.cn/simple  # 清华镜像源
Collecting Julia
  Downloading julia-0.6.2-py2.py3-none-any.whl.metadata (2.4 kB)
Downloading julia-0.6.2-py2.py3-none-any.whl (68 kB)
   ---------------------------------------- 68.8/68.8 kB 47.4 kB/s eta 0:00:00
Installing collected packages: Julia
Successfully installed Julia-0.6.2

其实,Julia中也要安装相应的给python调用的包(切换国内镜像源的教程可以参考这篇文章)。按]进入pkg模式:

xxxxx pkg > add PyCall

最后,在python中执行一次以下命令,让python按着julia的PyCall接口,找准你是什么julia版本,需要什么代码

>>> import julia
>>> julia.install() # 在比较新的版本中,如果你跳过上一步,没有安装julia包PyCall,python会在这一步给你安装。

至此,我们便可以愉快地调用julia中的程序了。

如果需要调用自己的Julia包,在python文件中写入:

from julia import Main  # 这一步之后,所有的julia函数你都能调用了

Main.eval("1+1")			# 调用Julia计算1+1
Main.sin(1) 				# 调用Julia的sin函数计算sin(1)
Main.include("./XXX.jl")  	# 运行julia的.jl文件,执行文件,将文件里面的函数写入Julia内核。

特意说一下,上面最后一行代码会执行这个文件,意味着我们可以在这个文件执行的时候预先做很多工作。比如:

  1. 让这个./XXX.jl文件include()几百个其它小文件;
  2. ./XXX.jl文件开头,加载自己或官方的Julia包。这些包里面export的函数在这个文件执行之后,也会全部加载到这个julia终端里面来。然后你就全部可以用Main.函数名()的方式引用。

但是Julia和Python各自都有海量的包,两种语言尝试沟通的时候,不可能照顾所有的数据格式。 比如pandas表格,传入Julia时不会自动转化成DataFrame。可以肯定的是,Julia除了支持list[number],dict,string,int那些基本的数值类型,还支持numpyArray类型——对应于julia的Array,Matrix,Vector


三、Tips about VS Code

如果你用到VSCode,可以在打开.jl代码时,点开设置-用户代码片段-julia.json,添加如下片段:

{
	// Place your snippets for julia here. Each snippet is defined under a snippet name and has a prefix, body and 
	// description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
	// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the 
	// same ids are connected.
	// Example:
	// "Print to console": {
	// 	"prefix": "log",
	// 	"body": [
	// 		"console.log('$1');",
	// 		"$2"
	// 	],
	// 	"description": "Log output to console"
	// }

	"My Julia Module":{
		"prefix": "MyModule",
		"body": [
			"try",
			"    global computername = ENV[\"COMPUTERNAME\"]",
			"catch",
			"    global computername = ENV[\"HOSTNAME\"]",
			"end",
			"if computername == \"家里电脑\"",
			"    push!(LOAD_PATH, \"E:/Documents/JuliaProgram/MyModules/\")",
			"elseif computername == \"宿舍电脑\"",
			"    push!(LOAD_PATH, \"F:/Documents/JuliaProgramme/MyModules\")",
			"elseif computername==\"DESKTOP-FDIN0I7\"",
			"    push!(LOAD_PATH, \"D:/Documents/Julia/MyModules\")",
			"elseif computername==\"TINA\"",
			"    push!(LOAD_PATH, \"D:/JuliaProgramme/MyModules\")",
			"end",
		]
	}
}

以后在.jl(julia文件)中键入MyModule就会出来这一整个片段。
python类似,就是.py文件时,编辑python.json文件。

  • 11
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值