PyCharm 在调用 issubclass() 后错误地假定对象是 BaseClass 的实例

问题描述 投票:0回答:1

我正在使用 Python 3.10.9 和 PyCharm 2022.2.1(社区版)运行此测试。这是 PyCharm 的问题,而不是 Python 本身。

在我的示例代码中,我使用了一个生成器方法,该方法将类类型作为参数,并构造该类。我想确保传递的类类型是

BaseClass
的子类,所以我在
issubclass()
参数上使用
class_type

class BaseClass:
    def __init__(self, foo):
        self.foo = foo


class SubClass(BaseClass):
    def __init__(self):
        super().__init__(foo='hi')
        self.bar = "hello"


def generate_sub_class(class_type):
    assert issubclass(class_type, BaseClass)
    new_obj = class_type()      # <--- PyCharm warning: "Parameter 'foo' unfilled"
    return new_obj


# Main
new_subclass = generate_sub_class(SubClass)
print(f"Type of new_subclass: {type(new_subclass)}")
print(f"new_subclass.foo: {new_subclass.foo}")
print(f"new_subclass.bar: {new_subclass.bar}")     # <--- PyCharm warning: "Unresolved attribute reference
                                                   #                        'bar' for class 'BaseClass'"

此代码在 Python 中运行时按预期工作,因为我们得到以下输出:

Type of new_subclass: <class '__main__.SubClass'>
new_subclass.foo: hi
new_subclass.bar: hello

但是,正如您在上面的代码中看到的那样,只要我调用

issubclass(class_type, BaseClass)
,PyCharm 现在就认为构造的对象是一个
BaseClass
对象。构造函数调用有一个警告,因为它正在查看错误的构造函数,并且 Main 中的
new_subclass.bar
调用有一个警告,因为它没有在
bar
中看到
BaseClass
,即使它是一个
SubClass
对象由 Python 输出验证。

有人知道为什么会这样吗?对我来说这似乎是一个 PyCharm 错误,我不知道为什么简单地调用

issubclass
会让 PyCharm 假设对象是 BaseClass。如果不调用
issubclass
,PyCharm 可以毫无问题地理解它是
SubClass
的一个实例。

在此先感谢您的帮助。

python python-3.x pycharm subclassing
1个回答
1
投票

我怀疑这不是真正的错误,而是不提供任何类型提示的副作用。 PyCharm 首先假定

class_type
作为类型
Any
,这意味着任何值都可以分配给名称,并且该值可以用于任何操作,无论类型如何。

那么 PyCharm 对

assert
语句做了什么?它尝试应用类型缩小,当断言为真时,为
class_type
分配比
Any
更具体的类型。作出断言
True
的最一般类型是
BaseClass
,因此在断言后面的代码中,它假设
class_type
的类型是
BaseClass
,而不是
Any
。 (如果断言失败,它不需要假设任何东西,因为下面的代码都不会执行。)

一旦类型缩小为

BaseClass
,其余的警告是不言自明的。
BaseClass
isn't 提供
BaseClass.__init__
期望的参数,并且
BaseClass
don't 的直接实例具有
bar
属性。

在运行时,一切都很好,因为没有关于

class_type
类型的假设;它
SubClass
,因此代码按预期执行。


就是说,我没有安装 PyCharm 来测试。

mypy
什么都不做,这让我怀疑与
mypy
相比,PyCharm 在执行类型缩小方面过于激进。如果您提供明确的类型提示会发生什么,例如,

from typing import TypeVar
T = TypeVar('T', bound=BaseClass)

def generate_sub_class(class_type: type[T]) -> T:
    assert issubclass(class_type, BaseClass)
    new_obj = class_type()
    return new_obj

在这里,类型提示提供了与

assert
语句可以推断出的相同数量的信息,但是由于类型提示已经暗示
T
可以绑定到
BaseClass
BaseClass
的子类,所以不类型缩小应该是必要的或应用的。

© www.soinside.com 2019 - 2024. All rights reserved.