为什么我的 Python 数据类没有正确初始化布尔值?
Why is my Python dataclass not initialising boolean correctly?
我目前正在为期权定价器编写一些代码,同时我一直在尝试使用 Python 数据classes。这里我有两个 classes,Option()
和 Option2()
,前者用数据 class 语法编写,后者用常规 class 语法编写。
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_american
也默认设置为False
。但是,无论出于何种原因,数据class 没有触发is_european: Optional[bool] = not is_american
,因此is_european
应该是True
.[= 时仍然是False
。 28=]
这是怎么回事?我是否错误地使用了我的数据class?
您的问题是:
is_european: Optional[bool] = not is_american
not is_american
在 定义 时间计算。在这一点上,is_american
是一个 Field
,并且所有 Field
都是真值。如果您想要根据另一个字段定义一个字段,您需要使用 post-initialization processing 在 is_american
初始化后动态地 select is_european
的值,或者使它成为一个@property
根据 is_american
的值实时计算其值(假设不可能同时成为两者)。
很可能是数据class 构造函数在处理语句的顺序方面遇到困难。例如,通常您会在任何可选参数之前拥有所有必需参数,并且它可能在构造时没有意识到该值是假的。
有一种内置机制可以确保以正确的顺序处理依赖于其他字段的字段。您需要做的是将您的辅助代码标记为 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
并使用 get()
来获取被调用的值。如果它总是与另一个值直接相关,则没有必要保留额外的值。只需在调用时即时计算即可。
对于许多语言,您不会直接访问属性,而是通过 get_is_american() 或 get_country() 等控制函数(get、set 等)访问它们。 Python 有一个很好的方法来通过装饰器处理这个问题。这允许在首次设置 class 时使用直接访问,然后转移到托管访问,而无需使用 @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)
您看到这种方法有多灵活了吗?如果您有更多的美国或欧洲国家,或者如果您认为该过程可能会扩展,您可以将存储更改为字符串或枚举并使用访问器定义 return 值。示例:
# 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
的现有代码,即使国家/地区现在已存储并作为字符串提供,访问代码的 none 也必须更改。
我目前正在为期权定价器编写一些代码,同时我一直在尝试使用 Python 数据classes。这里我有两个 classes,Option()
和 Option2()
,前者用数据 class 语法编写,后者用常规 class 语法编写。
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_american
也默认设置为False
。但是,无论出于何种原因,数据class 没有触发is_european: Optional[bool] = not is_american
,因此is_european
应该是True
.[= 时仍然是False
。 28=]
这是怎么回事?我是否错误地使用了我的数据class?
您的问题是:
is_european: Optional[bool] = not is_american
not is_american
在 定义 时间计算。在这一点上,is_american
是一个 Field
,并且所有 Field
都是真值。如果您想要根据另一个字段定义一个字段,您需要使用 post-initialization processing 在 is_american
初始化后动态地 select is_european
的值,或者使它成为一个@property
根据 is_american
的值实时计算其值(假设不可能同时成为两者)。
很可能是数据class 构造函数在处理语句的顺序方面遇到困难。例如,通常您会在任何可选参数之前拥有所有必需参数,并且它可能在构造时没有意识到该值是假的。
有一种内置机制可以确保以正确的顺序处理依赖于其他字段的字段。您需要做的是将您的辅助代码标记为 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
并使用 get()
来获取被调用的值。如果它总是与另一个值直接相关,则没有必要保留额外的值。只需在调用时即时计算即可。
对于许多语言,您不会直接访问属性,而是通过 get_is_american() 或 get_country() 等控制函数(get、set 等)访问它们。 Python 有一个很好的方法来通过装饰器处理这个问题。这允许在首次设置 class 时使用直接访问,然后转移到托管访问,而无需使用 @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)
您看到这种方法有多灵活了吗?如果您有更多的美国或欧洲国家,或者如果您认为该过程可能会扩展,您可以将存储更改为字符串或枚举并使用访问器定义 return 值。示例:
# 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
的现有代码,即使国家/地区现在已存储并作为字符串提供,访问代码的 none 也必须更改。