如何避免 Foo 类被视为 __main__.Foo?

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

出于组织目的,我将这两个类分为两个不同的文件(

foo.py
bar.py
Foo
Bar
。他们都实现了
__add__
方法。我希望两种
__add__
方法都能工作,无论
__other__
是类
Foo
还是
Bar
类的实例。

但是,如果

foo
是类
Foo
的实例并且
bar
是类
Bar
的实例,并且我尝试在模块 foo 中添加
bar + foo
Boo
__add__
方法会将 foo 视为
__main__.Foo
并提高
TypeError
。有问题的代码可以这样概括:

from typing import Union, Any

import bar as b

FooBar = Union['Foo', 'b.Bar']


class Foo:
    message: str

    def __init__(self, message: str) -> None:
        self.message = message

    def __add__(self, other: Any) -> 'Foo':
        if not isinstance(other, (Foo, b.Bar)):
            raise TypeError('can only add Foo and Bar')
        return Foo(' '.join((self.message, other.message)))


def test():
    foo = Foo('Jalim')
    bar = b.Bar('Rabei')
    foobar = foo + bar # works just fine
    print(foobar.message)
    barfoo = bar + foo # raises TypeError because it receives __main__.Foo
    print(barfoo.message)


if __name__ == '__main__':
    test()

from typing import Union, Any

import foo as f

FooBar = Union['f.Foo', 'Bar']


class Bar:
    message: str

    def __init__(self, message: str) -> None:
        self.message = message

    def __add__(self, other: Any) -> 'Bar':
        if not isinstance(other, (f.Foo, Bar)):
            print(f'{type(other) = }')
            raise TypeError('can only add Foo and Bar')
        return Bar(''.join((self.message, other.message)))

我知道我可以在另一个文件中运行

test()
,但我希望能够从
foo.py
运行,并在可能的情况下绕过从
Foo
__main__.Foo
的转换。

首先,我尝试使用类型别名

FooBar
而不是元组
(Foo, bar.Bar)
。但是,由于
FooBar
并不真正保存类型,而是保存
ForwardRef
,因此它不能在
isinstance
中使用。我也不能将
Foo
Bar
而不是
'Foo'
'b.Bar'
放入
Union
中,因为它会生成循环导入。

python python-import python-typing type-hinting python-class
1个回答
0
投票

使用这种结构,您的类

Foo
将被创建两次。它将以双重身份存在于两个独立的模块中,并具有两个不同的存储位置:

sys.modules["__main__"].Foo
sys.modules["foo"].Foo

出于所有实际目的,它们是不同的类型。

第一个是首先创建的,并且存在于顶级代码环境中(执行脚本时使用),第二个存在于

foo
模块命名空间中,在行
import b as bar
时创建被处决。

解决方案是将测试代码与库代码分开。

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