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

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

1 голос
/ 18 мая 2019

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

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

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

...