【问题标题】:Why do I need to cast the result of copy.deepcopy?为什么我需要转换 copy.deepcopy 的结果?
【发布时间】:2021-03-31 07:18:23
【问题描述】:

这是我为玩具类重载 __deepcopy__ 的尝试

import copy
from typing import Dict

class Foo:
    pass


class Bar:
    def __init__(self, foo: Foo):
        self._foo = foo

    def __deepcopy__(self, memo: Dict[int, object]) -> Bar:
        return Bar(copy.deepcopy(self._foo, memo))

然而,mypy 抱怨

错误:“Bar”的参数 1 具有不兼容的类型“object”;预期的“Foo”

我可以通过转换copy.deepcopy的结果来修复它

from typing import cast

    ...
    def __deepcopy__(self, memo: Dict[int, object]) -> Bar:
        return Bar(cast(Foo, copy.deepcopy(self._foo, memo)))

但这感觉没有必要。我这样做对吗?

编辑:我刚刚挖掘了typeshed repo,发现它们确实输入为

_T = TypeVar("_T")

def deepcopy(
    x: _T, memo: Optional[Dict[int, Any]] = ..., _nil: Any = ...
) -> _T: ...

我认为这应该可以避免cast

【问题讨论】:

  • @Carcigenicate 哦,所以它可能将self._foo 推断为object?真可惜

标签: python deep-copy type-hinting mypy


【解决方案1】:

deepcopy 的类型签名是对的

def deepcopy(x: _T, memo: Optional[Dict[int, Any]] = ..., _nil: Any = ...) -> _T: ...

将避免强制转换结果。

但是,这在 5 天前已在 https://github.com/python/typeshed/pull/4828 中修复。

所以,mypy 没有使用该类型定义,而是使用签名:

def deepcopy(x: _T, memo: Optional[Dict[int, _T]] = ..., _nil: Any = ...) -> _T: ...

您有 3 个选项:

  • 在此期间继续使用演员表
  • 克隆最新版本的typeshed 并使用配置选项custom_typeshed_dir
  • memo 的类型更改为Dict[int, Foo]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-07
    • 1970-01-01
    • 1970-01-01
    • 2021-10-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多