簡體   English   中英

什么是使用 python 數據類的沒有設置器的屬性獲取器的 pythonic 方式?

[英]What is a pythonic way to have property getters without setters with python dataclasses?

我有一種情況,我需要將變量 a、b 和 c 一起存儲在一個數據類中,其中c = f(a,b)和 a,b 可以突變。 打印 object 時,我需要c與 a 和 b 一起顯示,並且c不能更改,除非通過更改ab 我覺得做到這一點的最好方法是讓c成為使用屬性創建的值。

我嘗試使用的最小示例:

@dataclass
class Demo:
    a:int
    b:int
    c:int = field(init=False)

    @property
    def c(self) -> int:
        return self.a * self.b

但是,調用它會導致AttributeError: can't set attribute 我懷疑代碼試圖將 c 設置為field(init=False) ,但由於 c 沒有設置器而失敗。

我考慮過的選項(不包括我嘗試過的使代碼以不同方式崩潰的替代方案):

  • 初始化中沒有c
    • 在 repr、字段等中不顯示 c,這會導致進一步的問題
  • 有一個什么都不做的@c.setter
    • 這在技術上是可行的,但涉及編寫看似什么都不做的樣板代碼。
    • 擁有一個 function 永遠不會被我編寫的任何代碼顯式調用,但會使程序中斷被刪除感覺危險和不干凈。
    • 如果有人試圖直接修改 c,我還希望程序崩潰而不是默默地什么都不做。
  • 如上所述,但如果調用者不是__init__ (尾注中的函數),請在 setter 中使用sys._getframe().f_back.f_code引發錯誤
    • 只是一個 Cpython 實現細節。
    • 一般來說,使用標記為私有的函數是個壞主意。
  • 讓 Demo 不可變,在c中創建__post_init__ ,並使用dataclasses.replace修改 a 和 b。
    • 這在真空中工作,但Demo的其他用途(嗯,實際的東西,而不是最小的例子)要求它是可變的。

尾注:

    @c.setter
    def c(self, val):
        caller = sys._getframe().f_back.f_code.co_name
        if caller != '__init__':
            raise ValueError # or some other error

如果您希望c成為計算屬性,則完全取出c字段並保留該屬性:

@dataclass
class Demo:
    a:int
    b:int

    @property
    def c(self) -> int:
        return self.a * self.b

字段用於存儲數據, c不應該是。

如果您希望c出現在repr中,您必須自己編寫__repr__方法。 如果以后的代碼需要c顯示在fields中,那么您可能需要在更深層次上重新編寫代碼,並可能切換到dataclasses以外的東西。

您的方法c覆蓋您的字段c - 原始field聲明丟失,包括init=False

嘗試更改順序並使用default=參數。

from dataclasses import dataclass, field


@dataclass
class Demo:
    @property
    def c(self) -> int:
        return self.a * self.b

    a: int
    b: int
    c: int = field(init=False, default=c)


d = Demo(5, 10)
print(d)
d.a = 10
print(d)
d.c = 4  # generates an AttributeError

Output 來自 Python 3.8.0:

Demo(a=5, b=10, c=50)
Demo(a=10, b=10, c=100)
Traceback (most recent call last):
...
  File "/home/rob/src/plot/dc.py", line 20, in <module>
    d.c = 4  # generates an AttributeError
AttributeError: can't set attribute

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM