LoginSignup
3
5

More than 1 year has passed since last update.

pythonコードからjuliaへの移植-classとstructに着目して-

Last updated at Posted at 2022-02-12

pythonコードをjuliaへ移植したい

本記事は、julia初学者の視点で、既存のpythonコードをjuliaに書き写す方法について書きました。
特に、プログラミング初学者にとって、juliaにはpythonのようなclassがなく、どのようにしたらpythonコードをjuliaに移植できるのか、と悩む人が多いかと思ったので、その方法について書きました。

structのメリット

本題に入る前に、基礎事項であるstructの使い方を簡単に紹介します。
structは、オリジナルの型のことであり、そのメリットは、自ら定義した型に対して、演算が実行できることにある。

例えば自分で定義したオリジナルの型に対してベクトルの加法をしたい場合

struct Point
    x::Float64 #x, yをfieldと呼ぶらしい。
    y::Float64
end

function Base.:+(p::Point, q::Point)
    return Point(p.x + q.x, p.y + q.y)
end

実行

p = Point(1.0, 1.0)
q = Point(2.0, 3.0)

Base.:+(p, q) # Point(3.0, 4.0)
#以下と同じ
+(p, q) # Point(3.0, 4.0)

上記の例では、自分が決めたオリジナルの型(x,yというFloat64の型を持つデータ構造)に対して、ベクトルの加法を実行した。

例1:

以下pythonコードとjuliaコードを比較しながら、pythonコードをjuliaに移植する時のチップスをまとめる。

python

import random

class Mouse:
    def __init__(self, cry):
        self.cry = cry
    def greet(self):
        return self.cry
    def encode(self, msg):
        print(self.greet())
        ret = ""
        for m in msg:
            ret += random.choice(["chu", "kyu"])
        return ret

実行

h = Mouse("cyu-")
h.greet()

h.encode("おはようございます")

julia

  • juliaの構造体(struct)にはデータしか入らないため、pythonでいうclassのメソッドはない。

  • juliaでは、pythonのメソッド的なものを定義するために、juliaの関数の第一引数に構造体を入れることでメソッドに対応するものを作り出す

  • この第一引数に入れた構造体こそが、pythonのメソッドの第一引数に入るselfに対応

struct Mouse
    cry
end

function greet(self::Mouse) #functionの引数に構造体を代入する。
    return self.cry
end

function encode(self::Mouse, msg) #第一引数がselfに対応
    println(greet(self))
    ret = ""
    for m in msg
        ret *= rand(["chu", "kyu"])
    end
    return ret
end

実行

m = Mouse("chu-")
greet(m)
encode(m, "oha")

例2:モンテカルロ

もう1つ例を見る。

python

import numpy as np
class Monte:
    def __init__(self, n):
        self.n = n
    def calc_pi(self):
        c = 0
        for _ in range(self.n):
            x = np.random.random()
            y = np.random.random()
            if x * x + y * y <=1:
                c += 1
        return 4*c/self.n


m = Monte(100)
print(m.calc_pi())
# or
m = Monte(n=1000) 
m.n
print(m.calc_pi())

Julia

struct Monte
    n::Int # field
end

function calc_pi(m::Monte)
    c = 0
    for _ in 1:m.n
        x = rand()
        y = rand()
        if x^2 + y^2 <= 1
            c += 1
        end
    end
    return 4c / m.n
end

m = Monte(1000)
m.n # 1000
pi_approx = calc_pi(m)
@show pi_approx 

両者のコードを比べると、

  • 関数の引数に入るデータは、pythonでは__init__で定義されるが、juliaでは、structで定義されている。

  • pythonのclassで定義されているメソッドcalc_pi(self)が、juliaではcalc_pi関数に対応する。

  • calc_pi関数の引数には、structで定義されたデータ構造が代入されており、これがselfになっている。

まとめ

classとstructの両者の違いを具体的な例を通して確認しつつ、pythonコードからjuliaコードに移植する知見を得た。

まとめると、
まず、pythonコードを見比べて、classの__init__で定義されたデータをstructで定義する。次に、juliaではメソッドに対応するものとして関数を定義し、その第一引数にstructを代入することで、メソッドのようなものを作ることができる。

参考

pythonからjuliaに移行する際の心理的障壁をなくすための有益な知見が以下にまとめてある。
OOPMacro.jlの話

3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5