从其他文件导入类时,Python 3 isinstance意外行为?

时间:2019-05-18 00:04:18

标签: python python-3.x class python-import isinstance

我正在尝试从一个文件导入一个类,并检查该类是否在定义该文件的文件中作为该类的实例。问题是,这不是从True返回isinstance()函数,它返回False,因为它是在另一个文件中初始化的。

这是一个可行的示例。

假设您有file1.py

class Foo:
    def __init__(self, arg1):
        self.arg1 = arg1

def main(class_obj):
    # Prints false and is type <class 'file1.Foo'>
    print(type(class_obj))
    print(isinstance(class_obj, Foo))

if __name__ == '__main__':
    from file2 import get_class
    main(get_class())

还有file2.py

from file1 import Foo

def get_class():
    foo = Foo("argument")
    return foo

它打印False,类型为<class 'file1.Foo'>。我发现有趣的是,如果在定义的Foo中初始化file1类,它将返回True

# Add to main() function in file1
# Returns true and is type <class '__main__.Foo'>
foo_local = Foo("argument")  # Class initiated in __main__ seems to work
print(type(foo_local))
print(isinstance(foo_local, Foo))

我发现,如果在定义文件的外部启动一个类,则与在定义文件的内部启动该类相比,它是一个不同的“类”。

# Different Classes?
<class 'file1.Foo'>  # From other file (`file2.py`)
<class '__main__.Foo'>  # From same file (`file1.py`)

所以我的问题是:

如何解决此问题,以便即使在file1外部启动的类也可以在True函数上返回isinstance()?要改写它,如何使Foo类在file1.pyfile2.py中是“相同的”?如果重要,我使用Python 3.6.7。

1 个答案:

答案 0 :(得分:1)

最简单的答案是从不使用 if __name__=="__main__"。可以肯定,这是一个聪明的把戏,但是它并没有实现任何人认为的那样。本来应该使文件成为模块,但是(由于查找和运行模块和脚本的过程非常不同),实际上是让文件成为模块脚本,单独。这个技巧包含了有关此缺点的提示:模块中的__name__应该是其在sys.modules中的关键,如果它是“ __main__”,那根本不是任何普通模块。 (实际上可以import __main__并获取一个属性为脚本中全局变量的模块对象!)

在您的情况下,file1.py被用作脚本一次,然后通过模块file2作为模块被实际加载两次。每次加载都会创建一个不相关(如果相似)的类Foo在何处使用哪个类别都无所谓,而只使用哪个类别。 (file1甚至可以导入本身并获得“模块版本”。)请注意,这些类不必是“相同的”;同样的if技巧可以用来为他们提供不同的成员或基类,甚至可以控制执行哪个class Foo语句。

如果您要使用python -m,出于安装原因,这是一个非常合理的要求,则最省事的使用方式是通过软件包中的__main__.py通过import使用。仍然可以 导入它,这可能没有任何好处,但是没有人(除了天真的代码以递归方式导入包中的每个模块)。