Инструменты интроспекции Python долгое время имели плохую поддержку для вложенных классов. Имея объект класса невозможно узнать, где он был определён: внутри другого класса или на верхнем уровне модуля, и в первом случае так же не возможно узнать, в каком классе находится его определение. Так как использование вложенных классов часто признаётся дурным стилем программирования, то то, что единственная причина определения второго класса для того, чтобы получить возможность интроспекции другого вложенного класса, оказывается дурным каламбуром.
Python 3 лишь усилил данную проблему тем, что добавил несвязанные методы. В Python 2 при наличии такого определения класса:
class C: def f(): passВы могли получить из объекта C.f класс, в котором он определён:
>>> C.f.im_class <class '__main__.C'>Но такая возможность была убрана в Python 3:
>>> C.f.im_class Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'function' object has no attribute 'im_class' >>> dir(C.f) ['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']Это лишь ещё больше ограничило возможность интроспекции, доступную пользователю. Всё это в сумме создаёт проблемы при портировании на Python 3, например для библиотеки Twisted Core, где проблема с интроспекцией методов объектов возникала несколько раз. Кроме того, это ограничивает поддержку pickling.
Предложение
Данный PEP предлагает добавить в функции и классы дополнительный атрибут __qualname__. Для функций и классов верхнего уровня __qualname__ равен __name__. Для вложенных классов, методов и функций __qualname__ содержит путь, разделённый точками, ведущий к объекту с верхнего уровня модуля. Локальное пространство имён функции будет представлено в этом пути компонентом <locals>.
Примеры со вложенными классами
>>> class C: ... def f(): pass ... class D: ... def g(): pass ... >>> C.__qualname__ 'C' >>> C.f.__qualname__ 'C.f' >>> C.D.__qualname__ 'C.D' >>> C.D.g.__qualname__ 'C.D.g'Примеры со вложенными функциями
>>> def f(): ... def g(): pass ... return g ... >>> f.__qualname__ 'f' >>> f().__qualname__ 'f.<locals>.g'Ограничения
Для вложенных функций и классов, определённых внутри функций, по квалифицированному пути нельзя будет проследовать программно, так как пространство имён функции недоступно снаружи. Тем не менее, это будет полезнее для чтения человеком, чем простой атрибут __name__.
Так же как и атрибут __name__, атрибут __qualname__ вычисляется статически и автоматически не следует за переприсваиванием.
Обсуждение
Исключение имени модуля
Как и атрибут __name__, атрибут __qualname__ не включает имя модуля. Благодаря этому данные атрибуты не зависят от псевдонимов имён модулей или переприсваивания; кроме этого появляется возможность вычисления этих атрибутов в процессе компиляции.
Возрождение методов "отвязки" (unbound)
Возрождение методов отвязки поможет решить лишь часть проблем, решаемых данным PEP, причём за более высокую цену (добавление новых типов объектов и различных окольных путей, вместо дополнительного атрибута)
Выбор имени
"Квалифицированное имя" — лучший вариант, так как он вкратце описывает суть данного атрибута. Это не "полное имя" и не "полное квалифицированное имя", так как он, намеренно, не содержит имени модуля. Назвать его "путём" было бы неверно, так как это могло бы привести к путанице с путём файловой системы и атрибутом __file__.
Сперва было предложено назвать атрибут __qname__, но так как много людей (которые не знакомы с таким жаргоном, например из XML спецификации) сочли это название неочевидным, оно было заменено на менее короткое и более сложное __qualname__.
Комментариев нет:
Отправить комментарий