Как же так isinstance не работает?!
Эта статья о том, как важно быть последовательным. А также о том, почему иногда могут не работать проверки идентичности и наследования классов, и проверки принадлежности объекта к классу.
Пожалуй, большую часть из того, что я хочу сейчас вам рассказать правильнее было бы выразить в коде. Для наглядости. Итак, приступим:
Наверное, после запуска этого кода, особых пояснений больше не потребуется, однако пару слов я всё же скажу.
Итак, механизм импорта честно отрабатывает, выполняя то, что ему поручили, и в
И, если вам вдруг интересно, где (помимо этого странного кода выше) можно натолкнуться на такое поведение, то я скажу, что в любых проектах со множеством [вложенных] модулей есть такой шанс. Например, в Django, создатели которого вовсе не зря советуют придерживаться одного стиля импорта, не мешать абсолютные с относительными.
Будьте последовательны, не забывайте про тесты.
Удачи!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
''' | |
Тестируем влияние импорта на проверки идентичности классов. | |
* Создать директорию `imptest`. | |
* Переместиться в директорию `imptest` | |
* В директории `imptest` создать пустой файл `__init__.py`. | |
* В директории `imptest` создать файл `test.py`, поместить в него этот код. | |
* В директории `imptest` создать файл `class_a.py`. | |
* Поместить в `class_a.py` следующий код: | |
class A(object): | |
pass | |
* Запустить `test.py` | |
> python3 test.py | |
* Изучить результат. | |
''' | |
import sys | |
from os import path | |
sys.path.insert(0, path.dirname(path.dirname(path.realpath(__file__)))) | |
from class_a import A | |
from imptest.class_a import A as AA | |
print('\nИмпортируем один и тот же класс разными способами:') | |
print('from class_a import A') | |
print('from imptest.class_a import A as AA') | |
print() | |
print('A==A --> %s' % (A==A)) | |
print('AA==A --> %s' % (AA==A)) | |
print('isinstance(AA(), A) --> %s' % isinstance(AA(), A)) | |
print('\nПроход по атрибутам:') | |
for attr in dir(A): | |
if attr == '__dict__': | |
continue | |
val_a, val_aa = getattr(A, attr), getattr(AA, attr) | |
if val_a != val_aa: | |
print(' Разл.: %s' % attr) | |
if isinstance(val_a, str): | |
print(' "%s" VS "%s"' % (val_a, val_aa)) | |
print('\nПроход по sys.modules:') | |
for mod_name in sys.modules.keys(): | |
if mod_name.find('class_a') > -1: | |
print(' Найден %s' % mod_name) | |
print('\nБудьте последовательны в вопросах импорта.') | |
print('Да и в прочих тоже.') | |
print() |
Наверное, после запуска этого кода, особых пояснений больше не потребуется, однако пару слов я всё же скажу.
Итак, механизм импорта честно отрабатывает, выполняя то, что ему поручили, и в
sys.modules
появляется два разных модуля. Импортированный разными способами один и тот же класс, различается, помимо прочего, атрибутом __module__
, который был проставлен в момент создания типа.И, если вам вдруг интересно, где (помимо этого странного кода выше) можно натолкнуться на такое поведение, то я скажу, что в любых проектах со множеством [вложенных] модулей есть такой шанс. Например, в Django, создатели которого вовсе не зря советуют придерживаться одного стиля импорта, не мешать абсолютные с относительными.
Будьте последовательны, не забывайте про тесты.
Удачи!
На заметку
Зарегистрированные пользователи могут оценивать Книги, Видео, Статьи и прочее, а также добавлять их в избранное, для упрощения доступа к ним в будущем.