10 puan yazan ilotoki0804 2024-06-01 | 14 yorum | WhatsApp'ta paylaş
  • fieldenum, değer taşıyan (örneklenebilir) bir enum'dur.
  • Rust'taki alanlı enum'ları temiz bir şekilde destekler.
  • Fonksiyonel programlamanın saflığı ile Python'daki pratiklik arasında denge kurmaya çalışır.
  • Varsayılan olarak None için bir alternatif olan Option ile istisnalar için bir alternatif olan BoundResult desteği sunar.
  • Tamamen test edilmiştir.
  • İngilizce dokümantasyon henüz zayıf, ancak zamanla geliştirilmesi planlanıyor.
  • Issue, PR, star gibi her türlü destek memnuniyetle karşılanır.

14 yorum

 
savvykang 2024-06-02

dataclass'ın union tipi daha iyi olmaz mı diye düşünüyorum; bildirimin daha kısa olması dışında pek bir avantajını göremiyorum. fieldenum'un özellikle daha iyi olduğu noktalar var mı?

 
ilotoki0804 2024-06-03

Beyanının kısa ve sade olması, ayrıca yalnızca gerekli kısımları içermesi de büyük bir avantaj.
Örneğin,

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)  

Yukarıdaki fieldenum'u dataclass ile uygulamak isterseniz, bunu aşağıdaki gibi yazmanız gerekir.

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  

Kod uzuyor, okunması zorlaşıyor, hata yapma olasılığı artıyor ve çok da temiz göründüğü söylenemez, değil mi?

Elbette bu şekilde yazsanız bile, fieldenum'un sunduğu diğer pek çok özelliği de (generics, repr, __fields__, ...) elde edemezsiniz.

Bu nedenle, tüm bunları uygulayıp bir araya getiren fieldenum'un olması çok daha kullanışlıdır.

Bunun dışında, örnekler bölümündeki içeriklere de göz atmanız faydalı olabilir.

 
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 varsayılan olarak repr uygulamasını destekler
  2. dataclasses.fields, alan tanımları hakkında çalışma zamanı bilgisi sağlar
  3. Generic'ler typing modülü tarafından 3.5'ten beri, sözdizimsel kısayol ise 3.12'den beri destekleniyor
  4. Messages ad alanı söz konusu olduğunda, bu modülle uygulanabilir

Buna rağmen, class tanımları için gereken boilerplate kodun olmaması ve enum ile class'ı tek bir arayüzle kullanabilme avantajı kesinlikle öne çıkıyor. Ayrıntılı açıklama için teşekkürler

 
savvykang 2024-06-03

https://stackoverflow.com/a/47784683

Bu şekilde yapıları ifade etmeye yönelik çeşitli girişimler oldu, ancak sonuçta bunun Python'ın bir sınırı ve zayıf yönü olarak görülebileceğini düşünüyorum. ADT'yi (algebraic data type) okulda ilk kez OCaml ile görmüştüm; çalışırken bunu ancak bu şekilde taklit etmek zorunda olmak biraz üzücü geliyor.

ilotoki tarafından oluşturulan kütüphane, ADT'ye en çok yaklaşan örnek olarak görülebilir. Bir gün standart kütüphaneye dahil edilip yaygın olarak kullanılır hale gelirse güzel olur.

 
ilotoki0804 2024-06-03

Message uygulamasını Union ile yaparsanız yöntem kalıtımından yararlanamazsınız. Örneğin

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):  
        ...  

Yukarıdaki gibi .process yöntemini eklerseniz, tüm varyantlarda .process() yöntemini kullanabilirsiniz.

# Message.process() yöntemi her varyantta kullanılabilir  
Message.Quit.process()  
Message.Move(x=123, y=456).process()  
Message.Write("hello, world").process()  
Message.ChangeColor(123, 000, 89).process()  

Ayrıca bahsettiğim repr, 'ilgili enumun varyantı olarak repr' anlamındaydı.
Örneğin fieldenum, repr çağrısını sarmalayarak şu şekilde çalıştırır.

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

Özel bir __repr__ yoksa bunun Message enumunun alt varyantı olduğu bilgisi gösterilmez.

Quit, çağrı yapmadan kullanılan bir unit varyantıdır.

Message.Quit  # ayrı bir çağrıya (ör. `Message.Quit()`) gerek olmadan kullanılabilir  

Ayrıca çağrı gerektiren bir varyant türü olan fieldless varyantlarda, singleton oldukları için is işleciyle kontrol edebilirsiniz.

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

fieldenum kullanmak, bu şekilde gözden kaçması kolay çeşitli uygulama ayrıntılarını otomatik olarak ele almaya yardımcı olur.

 
wyatt216 2024-06-02

Acaba PyCon Korea'da bir sunum yapmayı düşünür müsünüz diye önermek istiyorum. Çok keyifle izledim; geliştirme sürecinde yaşadıklarınızı ve açıklamalarınızı doğrudan sizden dinlemek isterim!

 
ilotoki0804 2024-06-02

PyCon'da sunum yapabilirsem gerçekten büyük bir onur olur diye düşünüyorum. Sırf benim istememle olup olmayacağını bilmiyorum ama(^^;) düşüneceğim.

 
kayws426 2024-06-01

Ayrıca İngilizce README'de Option örneğinin de açıklanması iyi olurdu.
Option kolay anlaşılır ve daha aşina bir giriş noktası olabilir. Belgelerdeki açıklama sıralamasında Option'ı önce anlatmak da daha iyi olabilir gibi geliyor bana.

 
ilotoki0804 2024-06-01

İngilizce belge henüz hazır olmadığı için biraz yetersiz... Korece belge yeterince olgunlaştığında İngilizceye çevirmeyi düşünüyorum. Ya da ilgili PR'lar da memnuniyetle karşılanır!
Bana da önce Option'ı tanıtmanın daha iyi olacağı gibi görünüyor. Düzelteceğim.

 
kayws426 2024-06-01

Oo. İlginçmiş!!
Paylaştığınız Korece belge örnek kodunda düzeltilmesi gereken bir nokta var.

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()) #!!!!! burada value değil option olması gerekiyor gibi görünüyor !!!!!#  
  
value = hello()  
print_hello(value)  
 
ilotoki0804 2024-06-01

Bize bildirdiğiniz için teşekkürler. Düzelttik!

 
ilotoki0804 2024-06-01

Bunu GN olarak paylaşmam gerekiyordu ama yanlışlıkla genel olarak paylaşmışım;;

 
moderator 2024-06-01

Düzelttim.

 
ilotoki0804 2024-06-01

Teşekkürler~