Python 3 является неожиданным поведением при импорте класса из другого файла?

Я пытаюсь импортировать класс из одного файла и проверить, является ли экземпляр этого класса в файле, в котором он был определен. Проблема в том, что вместо возврата 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.py и file2.py ? Я Python 3.6.7, если это имеет значение.

Всего 1 ответ


Самый простой ответ - никогда не использовать if __name__=="__main__" . Конечно, это умный трюк, но он не делает то, что кто-то думает. Предполагается, что файл должен быть модулем и скриптом, но (поскольку процессы поиска и запуска модулей и скриптов настолько разные), он фактически позволяет файлу быть модулем или скриптом по отдельности . Уловка содержит подсказку об этом недостатке: предполагается, что __name__ в модуле является его ключом в sys.modules , а если это «__main__», то это вовсе не обычный модуль. (Фактически можно import __main__ и получить объект модуля, атрибуты которого являются глобальными переменными в скрипте!)

В вашем случае, когда file1.py используется один раз как скрипт, а затем, через модуль file2 , как модуль, он фактически загружается дважды . Каждая загрузка создает несвязанный (если похожий) класс Foo ; не имеет значения, где используется каждый класс, а какой именно. ( file1 может даже импортировать себя и получить «версию модуля».) Обратите внимание, что классы не обязательно должны быть «одинаковыми»; то же самое, if трюк, чтобы дать им разные члены или базовые классы, или даже контролировать, какой оператор class Foo выполняется.

Если вы хотите использовать python -m , что является вполне разумным желанием по причинам установки, наименее нарушенный способ его использования - через __main__.py в пакете, который в противном случае используется при import . Его все еще можно импортировать, что, вероятно, не принесет ничего хорошего, но никто (кроме наивного кода, который рекурсивно импортирует каждый модуль в пакете) не сделает этого.


Есть идеи?

10000