【问题标题】:Narrow Union by shape按形状缩小联合
【发布时间】:2021-12-12 14:30:27
【问题描述】:

如何按形状缩小Union?我不想用isinstance 或手动转换检查实际类型(有很多类型)。我也不能修改类型定义。

class X:
    title = "1"
class Y:
    name = "2"
class Z:
    name = "3"

for (i, r) in enumerate([X(), Y(), Z()]): # type of r: X | Y | Z

    if hasattr(r, "title"):
        print(r.title) # error
    else:
        print(r.name)  # error

类型检查错误说:

(variable) title: str | Unknown
Cannot access member "title" for type "Y"
  Member "title" is unknown
Cannot access member "title" for type "Z"
  Member "title" is unknown

(variable) name: Unknown | str
Cannot access member "name" for type "X"
  Member "name" is unknown

【问题讨论】:

  • 对我来说似乎是一个合法的 python 代码。你从哪里得到这个错误? Python 3.9.0 可以正确处理此代码。
  • @Sasha 使用 Pylance 进行类型检查时出错
  • 可能是版本问题? VSCode 中的 Pylance v2021.12.1 没有给我任何错误。或者我应该在那里启用一些东西?
  • 啊。我现在看到了。需要设置"python.analysis.typeCheckingMode": "basic"

标签: python python-3.x python-typing pylance


【解决方案1】:

问题

在某种程度上 Pylance 检查器是正确的。

类型不相关。相关类型不会出现校验错误:

class Base:
    title: str
    name: str

class X(Base):
    title = "1"
class Y(Base):
    name = "2"
class Z(Base):
    name = "3"

for (i, r) in enumerate([X(), Y(), Z()]): # type of r: X | Y | Z

    if hasattr(r, "title"):
        print(r.title) # no error
    else:
        print(r.name) # no error

另外,duck typing 在这里不适用,因为成员集不同。如果类型被认为是等价的,就不会出现错误:

class X:
    name: str
    title = "1"
class Y:
    name = "2"
    title: str
class Z:
    name = "3"
    title: str

for (i, r) in enumerate([X(), Y(), Z()]): # type of r: X | Y | Z

    if hasattr(r, "title"):
        print(r.title) # no error
    else:
        print(r.name) # no error

解决方法

虽然您可以欺骗 Pylance 检查器,使其不会抱怨代码,但有几个选项:

选项 1。Suppress 类型检查

class X:
    title = "1"
class Y:
    name = "2"
class Z:
    name = "3"

for (i, r) in enumerate([X(), Y(), Z()]): # type of r: X | Y | Z

    if hasattr(r, "title"):
        print(r.title) # type: ignore
    else:
        print(r.name) # type: ignore

选项 2. 使用 getattr 的动态访问而不是直接成员访问

class X:
    title = "1"
class Y:
    name = "2"
class Z:
    name = "3"

for (i, r) in enumerate([X(), Y(), Z()]): # type of r: X | Y | Z

    if hasattr(r, "title"):
        print(getattr(r, "title"))
    else:
        print(getattr(r, "name"))

【讨论】:

  • 我会等待一段时间才能接受这个,以期得到真正的解决方案
  • @OwnageIsMagic,是的,对不起。用更多细节更新了答案。
  • 我希望有这样的东西typescriptlang.org/play?#code/…
  • 顺便说一句,在您的第一个和第二个示例中,hasattr 检查始终为真
  • @OwnageIsMagic,不,不是 :) Base 将它们声明为没有默认值的实例变量。我的理解是,在这种情况下,Base 将表现为一个接口。
猜你喜欢
  • 2017-07-19
  • 2014-08-03
  • 1970-01-01
  • 1970-01-01
  • 2016-05-23
  • 2022-10-02
  • 1970-01-01
  • 2022-01-25
  • 2017-12-01
相关资源
最近更新 更多