10 poin oleh ilotoki0804 2024-06-01 | 14 komentar | Bagikan ke WhatsApp
  • fieldenum adalah enum yang memiliki nilai (dapat diinstansiasi).
  • Mendukung enum dengan field ala Rust secara rapi.
  • Berupaya menyeimbangkan kemurnian pemrograman fungsional dan kepraktisan di Python.
  • Secara bawaan mendukung Option sebagai alternatif untuk None dan BoundResult sebagai alternatif untuk exception.
  • Sudah diuji secara menyeluruh.
  • Dokumentasi bahasa Inggrisnya masih minim, tetapi ada rencana untuk terus melengkapinya secara bertahap.
  • Dukungan dalam berbagai bentuk seperti issue, PR, dan star semuanya sangat disambut.

14 komentar

 
savvykang 2024-06-02

Saya merasa union type pada dataclass mungkin lebih baik; selain deklarasinya yang lebih singkat, saya kurang melihat keunggulannya. Apakah ada hal yang membuat fieldenum secara khusus lebih unggul?

 
ilotoki0804 2024-06-03

Keunggulan besar lainnya adalah deklarasinya singkat, ringkas, dan hanya berisi bagian yang diperlukan.
Sebagai contoh,

from fieldenum import fieldenum, Variant, Unit  
  
  
@fieldenum  
class Message:  
    Quit = Unit  
    Move = Variant(x=int, y=int)  
    Write = Variant(str)  
    ChangeColor = Variant(int, int, int)  

Jika fieldenum di atas diimplementasikan dengan dataclass, kodenya harus ditulis seperti berikut.

from dataclasses import dataclass  
from typing import Self  
  
  
class Message:  
    Quit = Self  
    Move = Self  
    Write = Self  
    ChangeColor = Self  
  
  
class QuitMessageClass(Message, metaclass=ParamlessSingletonMeta):  
    pass  
  
QuitMessage = QuitMessageClass()  
  
  
@dataclass(frozen=True, kw_only=True)  
class MoveMessage(Message):  
    x: int  
    y: int  
  
  
@dataclass(frozen=True)  
class WriteMessage(Message):  
    _0: str  
  
  
@dataclass(frozen=True)  
class ChangeColorMessage(Message):  
    _0: int  
    _1: int  
    _2: int  
  
  
Message.Quit = QuitMessage  
Message.Move = MoveMessage  
Message.Write = WriteMessage  
Message.ChangeColor = ChangeColorMessage  

Kodenya menjadi lebih panjang dan lebih sulit dibaca, kemungkinan melakukan kesalahan juga lebih tinggi, dan rasanya juga tidak terlalu rapi, bukan?

Tentu saja, bahkan jika ditulis seperti ini pun Anda tidak akan mendapatkan berbagai fitur lain yang disediakan oleh fieldenum (generic, repr, __fields__, ...).

Karena itu, akan jauh lebih praktis jika ada fieldenum yang sudah mengimplementasikan dan mengumpulkan semua hal tersebut.

Selain itu, sepertinya ada baiknya juga melihat isi pada bagian contoh.

 
savvykang 2024-06-03
from dataclasses import dataclass  
  
@dataclass(frozen=True) # repr True by default  
class QuitMessage:  
    pass  
  
@dataclass(frozen=True, kw_only=True) # repr True by default  
class MoveMessage:  
    x: int  
    y: int  
  
@dataclass(frozen=True) # repr True by default  
class WriteMessage:  
    _0: str  
  
@dataclass(frozen=True) # repr True by default  
class ChangeColorMessage:  
    _0: int  
    _1: int  
    _2: int  
  
Message = QuitMessage | MoveMessage | WriteMessage | ChangeColorMessage  
  1. dataclass secara default mendukung implementasi repr
  2. dataclasses.fields menyediakan informasi runtime tentang definisi field
  3. Generic didukung sejak 3.5 oleh modul typing, dan syntactic sugar didukung sejak 3.12
  4. Untuk namespace Messages, ini bisa diimplementasikan sebagai modul

Meski begitu, ketiadaan kode boilerplate yang diperlukan untuk definisi class, serta kemampuan menggunakan enum dan class dengan satu antarmuka yang sama, tampaknya bisa menjadi kelebihan. Terima kasih atas penjelasan detailnya.

 
savvykang 2024-06-03

https://stackoverflow.com/a/47784683

Sudah ada berbagai upaya untuk mengekspresikan struktur seperti ini, tetapi pada akhirnya ini tampaknya bisa dianggap sebagai keterbatasan sekaligus kelemahan Python. Saya pertama kali mengenal ADT (algebraic data type) lewat OCaml saat kuliah, jadi agak disayangkan bahwa ketika bekerja kita hanya bisa menirunya dengan cara seperti ini.

Library yang dibuat oleh ilotoki mungkin bisa dianggap sebagai contoh yang paling mendekati ADT. Akan bagus jika suatu hari nanti ini masuk ke standard library dan digunakan secara luas.

 
ilotoki0804 2024-06-03

Jika implementasi Message dibuat dengan Union, Anda tidak bisa memanfaatkan pewarisan metode. Misalnya,

from fieldenum import fieldenum, Variant, Unit  
  
  
@fieldenum  
class Message:  
    Quit = Unit  
    Move = Variant(x=int, y=int)  
    Write = Variant(str)  
    ChangeColor = Variant(int, int, int)  
  
    def process(self):  
        ...  

Jika menambahkan metode .process seperti di atas, Anda bisa menggunakan metode .process() pada semua varian.

# Metode Message.process() dapat digunakan di setiap varian  
Message.Quit.process()  
Message.Move(x=123, y=456).process()  
Message.Write("hello, world").process()  
Message.ChangeColor(123, 000, 89).process()  

Selain itu, repr yang saya jelaskan mengacu pada "repr sebagai varian dari enum tersebut".
Sebagai contoh, jika repr dipanggil dengan pembungkus fieldenum, hasilnya berjalan seperti berikut.

print(repr(Message.Move(x=123, y=456)))  # Message.Move(x=123, y=456)  

Tanpa __repr__ kustom, fakta bahwa ia adalah subvarian dari enum Message tidak akan terlihat.

Quit adalah unit variant yang digunakan tanpa pemanggilan.

Message.Quit  # dapat digunakan tanpa pemanggilan terpisah (misalnya `Message.Quit()`)  

Selain itu, untuk jenis varian tanpa field yang memang harus menggunakan pemanggilan, Anda bisa memeriksanya sebagai singleton dengan operator is.

from fieldenum import fieldenum, Variant, Unit  
  
class WithFieldless:  
    Fieldless = Variant()  
  
assert WithFieldless.Fieldless() is WithFieldless.Fieldless()  

Dengan menggunakan fieldenum, hal ini membantu menangani secara otomatis berbagai detail implementasi yang mudah terlewat seperti ini.

 
wyatt216 2024-06-02

Bolehkah saya mengusulkan agar Anda membawakan presentasi ini di PyCon Korea? Saya sangat menikmatinya, jadi saya ingin langsung mendengar cerita dan penjelasan tentang proses pembuatannya dari Anda!

 
ilotoki0804 2024-06-02

Kalau bisa presentasi di PyCon, rasanya akan jadi kehormatan besar. Saya belum tahu apakah hanya karena saya ingin melakukannya berarti saya pasti bisa(^^;), tapi akan saya pertimbangkan.

 
kayws426 2024-06-01

Dan akan lebih baik jika contoh Option juga dijelaskan di README berbahasa Inggris.
Option mudah dipahami dan terasa familier untuk didekati. Dari urutan penjelasan di dokumentasi, rasanya akan lebih baik jika Option dijelaskan lebih dulu.

 
ilotoki0804 2024-06-01

Dokumentasi bahasa Inggrisnya masih belum siap sehingga saat ini agak minim... Saya berencana menerjemahkannya ke bahasa Inggris setelah dokumentasi bahasa Korea cukup matang. Atau, PR terkait juga sangat kami sambut!
Menurut saya, memperkenalkan Option lebih dulu juga tampaknya lebih baik. Akan saya perbaiki.

 
kayws426 2024-06-01

Wah, menarik sekali!!
Ada bagian yang perlu diperbaiki pada contoh kode di dokumen bahasa Korea yang Anda tautkan.

from fieldenum import fieldenum, Variant, Unit, unreachable  
from fieldenum.enums import Option  
  
def hello() -> Option:  # GOOD  
    return Option.Some("hello")  
  
def print_hello(option: Option):  # GOOD  
    print(value.unwrap()) #!!!!! Sepertinya di sini harusnya option, bukan value !!!!!#  
  
value = hello()  
print_hello(value)  
 
ilotoki0804 2024-06-01

Terima kasih sudah memberi tahu. Sudah saya perbaiki!

 
ilotoki0804 2024-06-01

Seharusnya saya unggah ke Show GN, tapi karena salah malah saya unggah sebagai postingan biasa;;

 
moderator 2024-06-01

Saya sudah memperbaikinya.

 
ilotoki0804 2024-06-01

Terima kasih~