ますきーた

mascii(ますきー)がQiita(きーた)に書いてなかった記事を書くブログ

PythonでもNode.jsでも動くコードを書いてみた

プログラミング初学者にとっては完全に毒記事でしかないので、今回はQiitaではなくこちらのブログに書きます。

PythonJavaScript は似ている文法を持っている(オブジェクト・辞書、配列・リスト、関数呼び出しなど)気がして、 簡単な計算なら共通コードで動作するのでは? という疑問が浮かび、2次方程式の解の公式の実装をしてみることにしました。

動作環境

書いたコード

複素数解も考慮します(Python なら複素数の計算も簡単ですが、JSはそうはいかないので実部と虚部に分けて計算しています)
変数はすべてグローバル変数です。snake_case, CamelCase みたいなルールはもはや適当です。

以下、シンタックスハイライトは JS です。

1//1# JS判定
is_js = 1 // 2

eval_js = eval
1 // int(not exec('eval_js = lambda x: None'))

eval_py = eval
eval_js("eval_py = () => {}")

eval_js("exec = () => {}")
exec_py = exec

1//1# Print関数を定義
eval_js("Print = console.log")
exec_py("Print = print")

1//1# JSのみstrを定義
eval_js("str = String")

1//1# 三項演算子 iif を定義
eval_js("iif = (c,x,y) => c ? x : y")
exec_py("iif = lambda c,x,y: x if c else y")

1//1# 代入演算子(?) Var を定義
1//1# 例) Var(x = 100), Var(x = 100, y = 200)
exec_py(
    "def Var(**kwargs):\n" +
    "    for k, v in kwargs.items():\n" +
    "        exec('global ' + k + ';' + k + ' = v')"
)
eval_js("Var = () => {}")

1//1# Hello, world!
Print("Hello, " + iif(is_js, "JavaScript", "Python") + "!")

1//1# 二次方程式の解を求める
a = 1
b = 3
c = 2

D = b ** 2 - 4 * a * c

if (D > 0) // 1:
    {
        Print("D = " + str(D) + " > 0"),
        Print("x = " + str((-b + D ** 0.5) / (2 * a)) + ", " + str((-b - D ** 0.5) / (2 * a)))
    }

if (D == 0) // 1:
    {
        Print("D = " + str(D)),
        Print("x = " + str(-b / (2 * a)))
    }

if (D < 0) // 1:
    {
        Var(re = -b / (2 * a), im = ((-D) ** 0.5) / (2 * a)),
        Print("D = " + str(D) + " < 0"),
        Print("x = " + str(re) + iif(im > 0, "+", "") + str(im) + "i, " + str(re) + iif(im < 0, "+", "") + str(-im) + "i")
    }

実行結果

(a,b,c)=(1,3,2)

Hello, JavaScript!
D = 1 > 0
x = -1, -2
Hello, Python!
D = 1 > 0
x = -1.0, -2.0

(a,b,c)=(1,4,5)

Hello, JavaScript!
D = -4 < 0
x = -2+1i, -2-1i
Hello, Python!
D = -4 < 0
x = -2.0+1.0i, -2.0-1.0i

工夫したこと

  • JSのコメントアウト // を積極的に活用
    • Python では切り捨て除算の演算子扱い
    • is_js = 1 // 2 で JS なら 1, Python なら 0 が入るような変数を作れた
  • とりあえず eval (JS, Python) と exec (Python) で必要そうな関数を定義
    • eval_js, eval_py, exec_py でそれぞれの言語でだけ引数の文字列を評価するようにした
    • 演算子は「数学的には、基本的には、関数をあらわすある種の糖衣構文のようなものに過ぎない」(by Wikipedia)ので、三項演算子を関数化
  • if に続く { ... } は JS だとブロック、Python だと集合扱いなので、Python に合わせて中身はすべて式にした
  • Var 関数
    • Python では受け取ったキーワード引数をグローバルに定義する
    • JS ではこの関数は何もしなくて良く、 Var(x = 1)x1 が代入される

わかったこと

  • Python でも文末の ; は使える
  • JS の代入は式だが Python 3.7 までの代入は文である
    • Python 3.8 で代入式 := が導入される可能性があることを知った
  • Python では intstr+ がエラーとなる
  • Python str は class, JS の String は関数
    • JS に慣れてしまっていて str が関数に見えてしまっていた
  • if 文まではなんとか JS でも Python でも解釈できるように書けたが、 elif や else は無理だった

所感

今回のコーディングはコードゴルフ的な要素がありますが、新しい発見があり両方の言語の勉強になって良かったです。