mypy: 在覆盖变量时赋值的类型不兼容

huangapple go评论102阅读模式
英文:

mypy: Incompatible types in assignment when overwriting a variable

问题

我在运行版本为0.942的mypy时遇到了“assignment”错误,但我无法理解。

我有一个名为price_point的变量,它采用字符串的形式,并根据字符串是否包含“-”来确定在传递给另一个函数_other_func()之前是否将该变量转换为列表。该变量也可以为None

尝试 1:

代码如下:

  1. def _other_func(
  2. price_points: Optional[Union[List[str], str]]
  3. ) -> float:
  4. return 1.0
  5. def get_rate(price_point: Optional[str]) -> float:
  6. """
  7. Args:
  8. price_point: 表示单个价格或价格范围的字符串,例如 '100' 或 '100-200'。也可以为None。
  9. """
  10. if price_point and len(price_point_range := price_point.split("-")) > 1:
  11. print(f"Checking range {price_point_range[0]} to {price_point_range[1]}")
  12. price_point = price_point_range
  13. return _other_func(price_point)

错误信息:

  1. error: Incompatible types in assignment (expression has type "List[str]", variable has type "Optional[str]") [assignment]
  2. price_point = price_point_range
  3. ^

有人能解释一下为什么mypy关心这个变量吗?因为_other_func()输入类型的联合中包含了List类型。我愿意听取其他建议。


尝试 2:

我认为问题可能与变量的名称有关,因此我尝试了以下方法来将变量重命名,然后将其传递给_other_func()

  1. def get_rate(price_point: Optional[str]) -> float:
  2. """
  3. Args:
  4. price_point: 表示单个价格或价格范围的字符串,例如 '100' 或 '100-200'。也可以为None。
  5. """
  6. if price_point and len(price_point_range := price_point.split("-")) > 1:
  7. print(f"Checking range {price_point_range[0]} to {price_point_range[1]}")
  8. price_point_input = price_point_range
  9. else:
  10. price_point_input = price_point
  11. return _other_func(price_point_input)

但是相同的错误仍然存在:

  1. error: Incompatible types in assignment (expression has type "Optional[str]", variable has type "List[str]") [assignment]
  2. price_point_input = price_point
  3. ^

我不确定是不是因为盯着屏幕看太久的缘故...

英文:

I'm getting an assignment error when running mypy version 0.942 on my script that I can't make sense of.

I have a variable price_point that takes the form of a string, and depending on if the string contains a "-", will determine if the variable is manipulated into a list before being passed to another function _other_func(). The variable can also be None.

Attempt 1:

The code:
<!-- language: python -->

  1. def _other_func(
  2. price_points: Optional[Union[List[str], str]]
  3. ) -&gt; float:
  4. return 1.0
  5. def get_rate(price_point: Optional[str])-&gt;float:
  6. &quot;&quot;&quot;
  7. Args:
  8. price_point: String representing single price or range of prices
  9. e.g. &#39;100&#39; or &#39;100-200&#39;. Can also be None.
  10. &quot;&quot;&quot;
  11. if price_point and len(price_point_range := price_point.split(&quot;-&quot;)) &gt; 1:
  12. print(f&quot;Checking range {price_point_range[0]} to {price_point_range[1]}&quot;)
  13. price_point = price_point_range
  14. return _other_func(price_point)

<!-- end snippet -->

Error returned:

  1. error: Incompatible types in assignment (expression has type &quot;List[str]&quot;, variable has type &quot;Optional[str]&quot;) [assignment]
  2. price_point = price_point_range
  3. ^

Can someone please explain why mypy is concerned about this variable, since the List type is accounted for in the Union of types in the _other_func() input? I'd be open to hearing alternate suggetions.


Attempt 2:

I thought the issue might be to do with the name of the variable, so I tried this alternative to rename the variable before passing it to _other_func():

<!-- language: python -->

  1. def get_rate(price_point: Optional[str])-&gt;float:
  2. &quot;&quot;&quot;
  3. Args:
  4. price_point: String representing single price or range of prices
  5. e.g. &#39;100&#39; or &#39;100-200&#39;. Can also be None.
  6. &quot;&quot;&quot;
  7. if price_point and len(price_point_range := price_point.split(&quot;-&quot;)) &gt; 1:
  8. print(f&quot;Checking range {price_point_range[0]} to {price_point_range[1]}&quot;)
  9. price_point_input = price_point_range
  10. else:
  11. price_point_input = price_point
  12. return _other_func(price_point_input)

<!-- end snippet -->

But the same error persists:

  1. error: Incompatible types in assignment (expression has type &quot;Optional[str]&quot;, variable has type &quot;List[str]&quot;) [assignment]
  2. price_point_input = price_point
  3. ^

I'm not sure if I'm just having one of those days of staring at the screen for too long...

答案1

得分: 2

静态类型在运行时不能改变。price_point 是一个 Optional[str] 类型,必须在调用 get_rate 函数的整个过程中保持不变。如果你想向 other_func 传递不同类型的值,你需要使用一个不同的变量,可以容纳字符串或列表(或 None):

  1. def get_rate(price_point: Optional[str]) -> float:
  2. """
  3. Args:
  4. price_point: 表示单个价格或价格范围的字符串,例如 '100' 或 '100-200',也可以是 None。
  5. """
  6. arg: Optional[Union[list[str], str]] = price_point
  7. if price_point and len(price_point_range := price_point.split("-")) > 1:
  8. print(f"Checking range {price_point_range[0]} to {price_point_range[1]}")
  9. arg = price_point_range
  10. return _other_func(arg)

然而,我可能会跳过新变量,只是调用 _other_func 两次,每次传递适当的参数:

  1. def get_rate(price_point: Optional[str]) -> float:
  2. """
  3. Args:
  4. price_point: 表示单个价格或价格范围的字符串,例如 '100' 或 '100-200',也可以是 None。
  5. """
  6. if price_point and len(price_point_range := price_point.split("-")) > 1:
  7. print(f"Checking range {price_point_range[0]} to {price_point_range[1]}")
  8. return _other_func(price_point_range)
  9. return _other_func(price_point)

更好的做法是考虑将这三种可能性统一到单一类型 list[str] 下,该类型应该包含 0、1 或 2 个字符串:

  1. def _other_func(
  2. price_points: list[str]
  3. ) -> float:
  4. match len(price_points):
  5. case 0:
  6. ... # 旧的 None 情况
  7. case 1:
  8. ... # 旧的字符串情况
  9. case 2:
  10. ... # 旧的 list[str] 情况
  11. case _:
  12. raise ValueError("列表中的项目太多")
  13. def get_rate(price_point: Optional[str]) -> float:
  14. arg: list[str]
  15. if not price_point:
  16. arg = []
  17. elif len(price_point_range := price_point.split("-")) > 1:
  18. print(f"Checking range {price_point_range[0]} to {price_point_range[1]}")
  19. arg = price_point_range
  20. else:
  21. arg = [price_point]
  22. return _other_func(arg)
英文:

Static types cannot be changed at runtime. price_point is a Optional[str], and it must stay that way for the duration of the call to get_rate. If you want to pass a value of a different type to other_func, you need to use a different variable that can hold either a string or a list (or None):

  1. def get_rate(price_point: Optional[str])-&gt;float:
  2. &quot;&quot;&quot;
  3. Args:
  4. price_point: String representing single price or range of prices
  5. e.g. &#39;100&#39; or &#39;100-200&#39;. Can also be None.
  6. &quot;&quot;&quot;
  7. arg: Optional[Union[list[str], str]] = price_point
  8. if price_point and len(price_point_range := price_point.split(&quot;-&quot;)) &gt; 1:
  9. print(f&quot;Checking range {price_point_range[0]} to {price_point_range[1]}&quot;)
  10. arg = price_point_range
  11. return _other_func(arg)

However, I would probably skip the new variable, and just make two calls to _other_func, each with the appropriate argument.

  1. def get_rate(price_point: Optional[str])-&gt;float:
  2. &quot;&quot;&quot;
  3. Args:
  4. price_point: String representing single price or range of prices
  5. e.g. &#39;100&#39; or &#39;100-200&#39;. Can also be None.
  6. &quot;&quot;&quot;
  7. if price_point and len(price_point_range := price_point.split(&quot;-&quot;)) &gt; 1:
  8. print(f&quot;Checking range {price_point_range[0]} to {price_point_range[1]}&quot;)
  9. return _other_func(price_point_range)
  10. return _other_func(price_point)

Even better, consider "unifying" the three possibilities under the single type list[str], which should hold 0, 1, or 2 strings.

  1. def _other_func(
  2. price_points: list[str]
  3. ) -&gt; float:
  4. match len(price_points):
  5. case 0:
  6. ... # Old None case
  7. case 1:
  8. ... # Old str case
  9. case 2:
  10. ... # Old list[str] case
  11. case _:
  12. raise ValueError(&quot;Too many items in the list&quot;)
  13. def get_rate(price_point: Optional[str])-&gt;float:
  14. arg: list[str]
  15. if not price_point:
  16. arg = []
  17. elif len(price_point_range := price_point.split(&quot;-&quot;)) &gt; 1:
  18. print(f&quot;Checking range {price_point_range[0]} to {price_point_range[1]}&quot;)
  19. arg = price_point_range
  20. else:
  21. arg = [price_point]
  22. return _other_func(arg)

huangapple
  • 本文由 发表于 2023年4月4日 03:49:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/75923270.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定