为什么我的Python数据类没有正确初始化布尔值?

我目前正在为期权定价编写一些代码,同时我一直在尝试使用 Python 数据类进行试验。这里我有两个类,Option()and Option2(),前者用数据类语法编写,后者用传统类语法编写。

from dataclasses import dataclass, field
from typing import Optional

@dataclass
class Option:
    is_american: Optional[bool] = field(default=False)
    is_european: Optional[bool] = not is_american

class Option2:
    def __init__(is_american=False):
        self.is_european = not is_american

if __name__ == "__main__":
    eu_option1 = Option()
    print(f"{eu_option1.is_european = }")
    
    eu_option2 = Option2()
    print(f"{eu_option2.is_european = }")

输出给出

eu_option1.is_european = False
eu_option2.is_european = True

然而,非常奇怪的事情发生了。注意在这种Option2()情况下,默认情况下is_american是如何设置False的,因此is_european必须是True并且确实如此,所以这是预期的行为。

但在这种dataclass Option()情况下,is_americanFalse默认设置为。但是,无论出于何种原因,数据类都没有触发is_european: Optional[bool] = not is_american,因此在它应该触发的时候is_european仍然FalseTrue

这里发生了什么?我是否错误地使用了我的数据类?

回答

数据类构造函数很可能在语句的顺序上挣扎。例如,通常您会在任何可选参数之前拥有所有必需参数,并且在构造时可能没有意识到该值是假的。

有一种内置机制可确保以正确的顺序处理依赖于其他字段的字段。您需要做的是将您的辅助代码标记为init=False并将它们移到一个__post_init__()方法中。

from dataclasses import dataclass, field
from typing import Optional, List

@dataclass
class Option:
    is_american: Optional[bool] = field(default=False)
    is_european: Optional[bool] = field(init=False)

    def __post_init__():
        self.is_european = not self.is_american

就我个人而言,如果它被调用,我会is_european完全摆脱并使用 aget()来获取值。如果它总是与另一个值直接相关,则没有必要保留额外的值。只需在调用时即时计算即可。

对于许多语言,您不会直接访问属性,而是通过控制函数(get、set 等)访问它们,例如 get_is_american() 或 get_country()。Python 有一个很好的方法来通过装饰器来处理这个问题。这允许在第一次设置类时使用直接访问,然后转移到托管访问,而无需更改使用@property装饰器调用属性的代码。例子:

# change the is_american to _is_american to stop direct access

# Get is the default action, therefore does not need to be specified
@property
def is_american(self):
    return self._is_american

@property
def is_european(self):
    return not self._is_american

# Allow value to be set
@property.setter
def is_american(self, america_based: bool):
    self._is_american = america_based

@property.setter
def is_european(self, europe_based: bool):
    self._is_american = not europe_based

这可以被称为如下:

print(my_object.is_american)
my_object.is_american = false
print(my_object.is_european)

你看到这种方法有多灵活了吗?如果您拥有比美国或欧洲更多的国家/地区,或者您认为流程可能会扩展,您可以将存储更改为字符串或枚举,并使用访问器定义返回值。例子:

# Imagine country is now a string
@property
def is_american(self):
    if self.country == 'US':
        return true
    else:
        return false

@property
def is_european(self):
    if self.country == 'EU':
        return true
    else:
        return false

@property
def country(self):
    return self._country

@property.setter
def country(self, new_country: str):
    self._country = new_country

@property.setter
def is_american(self, america_check: bool):
    if america_check:
        self._country = "US"
    else:
        self._country = "EU"

@property.setter
def is_european(self, europe_check: bool):
    if europe_check:
        self._country = "EU"
    else:
        self._country = "US"

请注意,如果您已经拥有调用 的现有代码,那么is_american即使国家/地区现在已存储并作为字符串可用,也无需更改任何访问代码。


以上是为什么我的Python数据类没有正确初始化布尔值?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>