簡體   English   中英

如何不在 Python 中將數據類成員實例化為類變量?

[英]How to not instantiate dataclass members as class variables in Python?

默認情況下,Python 似乎將類成員視為 ClassVar。 雖然來自文檔: https : //docs.python.org/3/library/dataclasses.html#class-variables

dataclass() 實際檢查字段類型的兩個地方之一是確定字段是否是 PEP 526 中定義的類變量。它通過檢查字段的類型是否為 Typing.ClassVar 來實現。 如果字段是 ClassVar,則將其作為字段排除在外,並被數據類機制忽略。 模塊級 fields() 函數不會返回此類 ClassVar 偽字段。

問題的最小再現:

from dataclasses import dataclass
import numpy as np

@dataclass
class Color:
    r: int = 0
    g: int = 0
    b: int = 0

@dataclass
class NumberColor:
    color: Color = Color()
    number: int = 0
    alpha = np.zeros(3)

x = NumberColor()
y = NumberColor()

print("Id of x:", id(x))
print("Id of y:", id(y))
print('-----------')
print("Id of x.color:", id(x.color))
print("Id of y.color:", id(y.color))
print('-----------')
print("Id of x.number:", id(x.number))
print("Id of y.number:", id(y.number))
print('-----------')
print("Id of x.alpha:", id(x.alpha))
print("Id of y.alpha:", id(y.alpha))
print('-----------')

x.color.r = 255
x.number = 10

print(x.__dict__)
print(y.__dict__)

產量:

Id of x: 140660354709392
Id of y: 140660357249008
-----------
Id of x.color: 140660355994096
Id of y.color: 140660355994096
-----------
Id of x.number: 9788960
Id of y.number: 9788960
-----------
Id of x.alpha: 140660289932624
Id of y.alpha: 140660289932624
-----------
{'color': Color(r=255, g=0, b=0), 'number': 10}
{'color': Color(r=255, g=0, b=0), 'number': 0}

不,您的NumberColor類的color屬性不被視為類變量。 相反,它是由dataclass裝飾器為您的類創建的__init__方法的共享默認參數。

它與可變默認參數的任何其他問題沒有太大不同:

def foo(c = Color()): # default value is created here
    return c

x = foo()    # get the default value
print(x.r)   # 0, as is expected
x.r = 255

y = foo()    # get the default again
print(y.r)   # 255, not 0 as you might naively expect

在您的代碼中,與xy等效的是x.colory.color屬性。

為避免此問題,您可以使用作為Color類的default_factory參數將dataclasses.field對象分配給類主體中的名稱(您還需要對用作alpha的默認值的 numpy 數組執行類似操作) :

from dataclasses import dataclass, field

@dataclass
class NumberColor:
    color: Color = field(default_factory=Color)         # use a field!
    number: int = 0
    alpha = field(default_factory=lambda: np.zeros(3))  # here too

不需要將field用於number (或用於Color的屬性),因為int對象是不可變的,並且您不應該關心是否將相同的對象用於任何給定的0值。

暫無
暫無

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

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