Проблемы модуля `inspect`.Модуль
inspect в питоне – сборник костылей и легаси.
Если вы не любите людей, то можете спрашивать их:
1. Чем отличается
typing.get_type_hints от
inspect.get_annotations? А от
annotationslib.get_annotations?
2. Какие проблемы есть у
getargvalues?
3. Чем отличаются
getargs,
getfullargspec и
singature?
4. В чем разница между
inspect.iscoroutinefunction и
asyncio.iscoroutinefunction? А между
inspect.iscoroutine и
asyncio.iscoroutine?
5. Чем будет отличаться
inspect.getmembers от
inspect.getmembers_static?
6. Как конкретно работает получение сигнатуры у разных объектов? 😱
Некоторое время назад я взялся исправить несколько самых сломанных частей:
https://github.com/python/cpython/issues/108901И даже сделал пакет с бекпортами для <=3.13:
https://github.com/wemake-services/inspect313Но все опять оказалось совсем не просто. Я не успел до фича фриза в 3.13, так что надеюсь, что успею в 3.14
Что сломано?Например:
inspect.getargvalues. Оно не работает с pos-only параметрами:
>>> import inspect
>>> def func(a: int = 0, /, b: int = 1, *, c: int = 2):
... return inspect.currentframe()
>>> frame = func()
>>> # notice that pos-only and kw-only args are not supported properly:
>>> inspect.formatargvalues(*inspect.getargvalues(frame))
'(a=0, b=1, c=2)'
Должно быть так:
>>> from inspect import Signature
>>> str(Signature.from_frame(frame)) # this API does not exist yet
'(a=0, /, b=1, *, c=2)'
Но, возникает вопрос: а нужно ли вообще добавлять такой метод? Насколько полезено получать сигнатуры из фреймов и код-обжектов?
Далее:
getfullargspec. Он не поддерживает pos-only параметры и не совсем корректно работает с параметрами
self,
cls, тд.
>>> import inspect
>>> class A:
... def method(self, arg, /): ...
>>> inspect.getfullargspec(A.method)
FullArgSpec(args=['self', 'arg'], varargs=None, varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={})
>>> inspect.getfullargspec(A().method).args # must not report `self`! :(
['self', 'arg']
>>> inspect.signature(A.method)
<Signature (self, arg, /)>
>>> inspect.signature(A().method)
<Signature (arg, /)>
Но, все-таки работа ведется довольно активно:
-
asyncio.iscoroutinefunction уже задепрекейчена:
https://github.com/python/cpython/pull/122875 Скоро будет только версия из
inspect- Добавили
annotationslib.get_annotations (которая переехала из
inspect и теперь будет самым-правильным-способом™):
https://github.com/python/cpython/blob/9e108b8719752a0a2e390eeeaa8f52391f75120d/Lib/annotationlib.py#L582 - Пофиксили кучу багов
Для чего `inspect` можно использовать на практике?Я пользовался
inspect.signature только для создания рантайм имплементациия каррирования для
dry-python/returns:
https://github.com/dry-python/returns/blob/master/returns/curry.pyДовольно много библиотечного кода используют
inspect для интроспекции в самых неожиданных местах:
-
https://github.com/search?type=code&q=inspect.iscoroutinefunction-
https://github.com/search?type=code&q=inspect.getfullargspec-
https://github.com/search?type=code&q=inspect.getargvaluesРасскажите: а у вас были проблемы с
inspect? Если да, то какие?