简体   繁体   English

从不同的文件导入类时,Python 3是否存在意外行为?

[英]Python 3 isinstance unexpected behavior when importing class from different file?

I am trying to import a class from one file and check if is an instance of that class in the file that it was defined in. The problem is that instead of returning True from the isinstance() function, it returns False , because it was initialised in a different file. 我试图从一个文件导入一个类,并检查它是否是在其定义的文件中的该类的实例。问题是,而不是从isinstance()函数返回True ,它返回False ,因为它是在另一个文件中初始化。

Here is a working example. 这是一个有效的例子。

Say you have file1.py : 假设你有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())

And file2.py : file2.py

from file1 import Foo

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

It prints False and the type is <class 'file1.Foo'> . 它打印False ,类型为<class 'file1.Foo'> What I found interesting is that if you initialize the Foo class in file1 where is was defined, it returns True . 我发现有趣的是,如果在file1中初始化Foo类,其中定义了is,则返回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))

I found that if you initiate a class outside of the file where it is defined, it is a different "class" than if you initiate the class inside the file where it was defined. 我发现如果你在定义它的文件之外启动一个类,它就是一个不同的“类”,而不是你在定义它的文件中启动类。

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

So my question is: 所以我的问题是:

How can I work around this so that even the classes initiated outside of the file1 can return True on the isinstance() function? 我如何解决这个问题,以便即使在file1之外启动的类可以在isinstance()函数上返回True To reword it, how can I make it so that the Foo class is the "same" in file1.py and file2.py ? 要重新编写它,我怎样才能使Foo类在file1.pyfile2.py “相同”? I Python 3.6.7 if it matters. 我是Python 3.6.7如果重要的话。

The starkly simple answer is to never use if __name__=="__main__" . 简单的答案是永远不要使用 if __name__=="__main__" It's a clever trick, to be sure, but it doesn't do what anyone thinks it does. 当然,这是一个聪明的伎俩,但它没有做任何人认为它做的事情。 It's supposed to make a file be a module and a script, but (because the processes for finding and running modules and scripts are so different) what it actually does is let the file be a module or a script, separately . 它应该做一个文件是一个模块一个脚本,而是(因为查找和运行模块和脚本是如此不同的过程),它实际上做的是让该文件是一个模块脚本, 分别 The trick contains a hint as to this shortcoming: __name__ in a module is supposed to be its key in sys.modules , and if it's “__main__” that's not any normal module at all. 这个技巧包含了一个关于这个缺点的提示:模块中的__name__应该是它在sys.modules关键,如果它是“__main__”则根本不是任何正常的模块。 (It is in fact possible to import __main__ and get a module object whose attributes are the global variables in the script!) (实际上可以import __main__并获取一个模块对象,其属性是脚本中的全局变量!)

In your case, where file1.py gets used once as a script and then, via the module file2 , as a module, it is actually loaded twice . 在您的情况下, file1.py作为脚本使用一次,然后通过模块file2作为模块,实际上加载了两次 Each load creates an unrelated (if similar) class Foo ; 每个加载创建一个不相关的(如果相似)类Foo ; it doesn't matter where each class is used, just which one. 每个类的使用位置无关紧要,只需使用哪一个。 ( file1 could even import itself and would get the “module version”.) Note that the classes need not be “the same”; file1甚至可以导入自己并获得“模块版本”。)请注意,类不必“相同”; the very same if trick could be used to give them different members or base classes, or could even control which class Foo statement is executed. if可以使用技巧为它们提供不同的成员或基类,或者甚至可以控制执行哪个class Foo语句。

If you want to use python -m , which is a perfectly reasonable desire for installation reasons, the least broken way of using it is via a __main__.py in a package otherwise used via import . 如果你想使用python -m ,这是一个非常合理的安装理由,那么使用它的简单的方法是通过一个包中的__main__.py ,否则通过import It's still possible to import it, which probably doesn't do anything good, but no one (aside from naïve code that recursively imports every module in a package) will do so. 仍然可以导入它,这可能没有任何好处,但没有人(除了递归导入包中的每个模块的天真代码)将这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM