Konversi nilai

Mengirim angka, string, dan sekuens melintasi batas Mojo dan Python dua arah.

Daftar isi

Nilai yang melintasi batas Mojo dan Python tidak selalu dapat dipakai langsung di sisi tujuannya, karena kedua arah batas itu berlaku berbeda. Topik ini membahas konversi nilai dua arah, yaitu membongkar PythonObject menjadi tipe Mojo yang tepat, membangun sekuens Python dari Mojo, serta mengirim nilai Mojo agar diterima sebagai objek Python yang wajar. Setelah topik ini dibaca, angka, string, dan kumpulan nilai dapat dikirim bolak-balik dengan tipe yang benar di kedua sisi batas.

Konversi Python ke Mojo dengan konstruktor tipe#

Nilai Python yang tersimpan dalam PythonObject tidak dikonversi otomatis menjadi tipe Mojo. Compiler menolak penugasan langsung dengan pesan cannot implicitly convert 'PythonObject' value to 'Float64', sehingga setiap nilai yang akan digunakan sebagai angka Mojo wajib dibongkar secara eksplisit. Alatnya adalah konstruktor tipe, yakni konstruktor Int, Float64, Bool, dan String yang menerima argumen kata kunci py berisi PythonObject yang akan dikonversi.

Program berikut membuat empat nilai Python melalui Python.evaluate, mengonversinya satu per satu, lalu mencetak hasilnya. Ekspresi 10 / 3 menghasilkan pecahan Python, 2**40 menghasilkan bilangan bulat Python yang besar, sedangkan dua ekspresi terakhir menghasilkan nilai boolean dan string. Simpan kode berikut sebagai konversi-python-ke-mojo.mojo.

mojo konversi-python-ke-mojo.mojo
from std.python import Python

def main() raises:
    var py_float = Python.evaluate("10 / 3")
    print(py_float)
    print(Float64(py=py_float))

    var py_int = Python.evaluate("2**40")
    print(Int(py=py_int))

    var py_bool = Python.evaluate("10 > 5")
    print(Bool(py=py_bool))

    var py_str = Python.evaluate("'hijau'")
    print(String(py=py_str))
bash
# jalankan program konversi python ke mojo
mojo run konversi-python-ke-mojo.mojo
text Keluaran
3.3333333333333335
3.3333333333333335
1099511627776
True
hijau

Keluaran memperlihatkan hasil setiap konversi secara berurutan. Dua baris pertama berisi 3.3333333333333335, yaitu nilai py_float yang dicetak dua kali, sekali sebagai PythonObject dan sekali setelah dikonversi menjadi Float64, sehingga presisinya identik. Nilai 2**40 sebesar 1099511627776 masih muat dalam Int Mojo, sedangkan True dan hijau menunjukkan konversi Bool dan String mempertahankan nilai aslinya. Pilihlah konstruktor yang sesuai dengan isi PythonObject agar nilai yang dikonversi tidak berubah maknanya, lalu simpan hasilnya dalam variabel bertipe sebelum digunakan lebih lanjut.

Sekuens Python yang dibangun dari Mojo#

Sekuens, yakni kumpulan nilai berurutan seperti list Python, dibangun dari Mojo dengan Python.list. Fungsi ini menerima argumen sebanyak apa pun dan mengembalikan PythonObject yang berupa list Python sungguhan. Karena list yang dihasilkan asli, metode Python seperti append dapat dipanggil langsung, pengindeksan menggunakan kurung siku, len menghitung jumlah anggotanya, dan perulangan for-in mengunjungi setiap butir yang tetap berupa PythonObject.

Program berikut menyusun list buah, menambahkan satu anggota, lalu membaca isinya melalui beberapa cara yang berbeda. Simpan kode berikut sebagai koleksi-python.mojo.

mojo koleksi-python.mojo
from std.python import Python

def main() raises:
    var buah = Python.list("apel", "jeruk", "pisang")
    buah.append("mangga")
    print(buah)
    print(buah[1])
    print(len(buah))
    for b in buah:
        print(b)
bash
# jalankan program koleksi python
mojo run koleksi-python.mojo
text Keluaran
['apel', 'jeruk', 'pisang', 'mangga']
jeruk
4
apel
jeruk
pisang
mangga

Baris pertama keluaran adalah cetakan list itu sendiri yang mengikuti format Python, lengkap dengan tanda kutip dan kurung siku. Baris kedua mengambil anggota kedua melalui buah[1], baris ketiga menunjukkan len menghitung empat anggota, dan empat baris terakhir berasal dari perulangan for-in. Perlu dicatat bahwa list ini hidup di sisi Python, sehingga seluruh perubahan terhadapnya mengikuti aturan Python, bukan aturan koleksi Mojo seperti List.

Mengirim nilai Mojo ke Python#

Arah sebaliknya tidak memerlukan panggilan konversi khusus, karena nilai Mojo yang dilewatkan sebagai argumen otomatis dibungkus menjadi objek Python. Yang perlu disiapkan hanyalah fungsi Python yang menerima nilai tersebut. Fungsi itu boleh berasal dari modul yang diimpor, atau didefinisikan langsung di dalam program Mojo melalui Python.evaluate dengan argumen file=True, yang mengeksekusi teks sumber yang panjang sebagai satu modul dan mengembalikan objek modulnya.

Program berikut menanamkan fungsi type_printer yang mencetak tipe argumennya dari sisi Python, lalu memanggilnya dengan empat nilai Mojo yang berbeda. Simpan kode berikut sebagai konversi-mojo-ke-python.mojo.

mojo konversi-mojo-ke-python.mojo
from std.python import Python

def main() raises:
    var py_module = """
def type_printer(value):
    print(type(value))
"""
    var py_utils = Python.evaluate(py_module, file=True, name="py_utils")

    py_utils.type_printer(4)
    py_utils.type_printer(3.14)
    py_utils.type_printer(True)
    py_utils.type_printer("Mojo")
bash
# jalankan program konversi mojo ke python
mojo run konversi-mojo-ke-python.mojo
text Keluaran
<class 'int'>
<class 'float'>
<class 'bool'>
<class 'str'>

Empat baris keluaran dicetak oleh sisi Python. Bilangan bulat Mojo 4 tiba sebagai int, pecahan 3.14 tiba sebagai float, nilai boolean tiba sebagai bool, dan string Mojo tiba sebagai str. Pembungkusannya terjadi otomatis pada setiap persilangan batas, sehingga fungsi Python tidak perlu mengetahui bahwa pemanggilnya adalah Mojo, dan argumen yang sama diproses sebagaimana bila dipanggil dari Python.

Kesalahan umum#

Kesalahan yang sering muncul adalah mengharapkan metode konversi pada PythonObject. Program berikut memanggil to_float64() pada PythonObject yang berisi pecahan Python, dan panggilan itu berakhir dengan error karena objek float milik Python tidak memiliki metode tersebut. Simpan kode berikut sebagai metode-hilang.mojo.

mojo metode-hilang.mojo
from std.python import Python

def main() raises:
    var builtins = Python.import_module("builtins")

    var f = builtins.float("3.75")
    try:
        print(f.to_float64())
    except e:
        print("error:", e)

    print(Float64(py=f))
bash
# jalankan program metode yang hilang
mojo run metode-hilang.mojo
text Keluaran
error: 'float' object has no attribute 'to_float64'
3.75

Pesan 'float' object has no attribute 'to_float64' menyatakan bahwa PythonObject meneruskan akses metode ke objek Python di baliknya, dan objek float Python tidak menyediakan metode Mojo mana pun. Perbaikannya adalah menggunakan konstruktor tipe sebagaimana baris terakhir program, yang mencetak 3.75 dengan benar. Kesalahan kedua adalah menugaskan PythonObject langsung ke variabel bertipe Mojo. Penugasan itu ditolak compiler dengan pesan cannot implicitly convert 'PythonObject' value to 'Float64', sehingga konversi eksplisit tetap diperlukan pada setiap batas dan di kedua arah tanpa kecualian.

Kesalahan ketiga adalah memperlakukan hasil Python.list sebagaimana koleksi Mojo, misalnya mengharapkan tipe elemen yang seragam atau metode milik List Mojo. Nilainya tetap objek Python, sehingga metode yang tersedia adalah metode Python, dan tipe tiap anggotanya ditentukan oleh Python pula. Cara yang tepat adalah membaca objeknya mengikuti kebiasaan Python sampai konversi dilakukan, kemudian melanjutkan pekerjaan dengan tipe Mojo setelah nilai yang dibutuhkan sudah dibongkar.

Ringkasan#

  • PythonObject tidak dikonversi otomatis, dan konstruktor Int, Float64, Bool, serta String dengan argumen py membongkarnya secara eksplisit menjadi tipe Mojo.
  • Python.list membangun list Python sungguhan dari Mojo, lengkap dengan append, pengindeksan, len, dan perulangan for-in.
  • Nilai Mojo yang dikirim sebagai argumen otomatis dibungkus menjadi int, float, bool, atau str di sisi Python.
  • Konversi eksplisit wajib dilakukan di kedua arah, karena penugasan langsung PythonObject ke tipe Mojo ditolak compiler.

Referensi#