DeepCode предлагает статический анализ программ на основе ИИ для Java, JavaScript и TypeScript, C/C++ и Python. Как вы, возможно, знаете, DeepCode использует тысячи репозиториев с открытым исходным кодом для обучения нашего движка. Мы попросили команду разработчиков предоставить некоторую статистику по результатам. Что касается основных предложений от нашего движка, мы хотим представить и дать некоторую информацию в этой серии статей в блоге.

Язык: Python
Дефект: X — неизменяемый объект, и одному из его элементов присвоено значение
Диагностика: Код пытается записать элемент в экземпляре неизменяемого типа данных

Я нашел этот пример в monkeylyf/interviewjam и, как обычно, вы можете открыть репозиторий в DeepCode и следовать дальше. Ниже приведен фрагмент панели инструментов в DeepCode:

def findCelebrityWithExtraSpace(self, n):
    """
    :type n: int
    :rtype: int
    """
    stack = range(n)
...
            stack[-2] = a
...

DeepCode дает нам обратную связь: «Попытка сохранить значение в элементе диапазона неизменяемого типа (от вызова до диапазона) приведет к сбою». Но разве range() не возвращает список? Ну, это когда-то было...

Давайте воспроизведем то, что происходит в интерпретаторе Python:

Python 3.8.1 (tags/v3.8.1:1b293b6, Dec 18 2019, 22:39:24) [MSC v.1916 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> stack = range(10)
>>> stack
range(0, 10)
>>> a = stack[-1]
>>> stack[-2] = a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'range' object does not support item assignment
>>>

Здесь мы вызываем функцию range(). В Python3 это переименованная версия функции xrange() Python2. Это означает, что на самом деле он не создает список с последовательностью значений. Скорее, он использует yield для получения конкретного значения, когда это необходимо, вместо хранения огромных объемов данных. Вот почему Python говорит, что range объект не поддерживает назначение элементов. И, кстати, он также не поддерживает функцию pop(), которая используется в примере кода.

В приведенном выше примере кода приложение аварийно завершало работу при попытке записи в объект range. Тем не менее, поскольку диапазоны часто используются в качестве секвенсора для циклов, диапазоны могут быть довольно большими. Таким образом, имеет смысл использовать такой объект диапазона вместо списка. Тем не менее, если вам нужен список в качестве хранилища данных, как в нашем примере здесь, есть простой способ получить lists с последовательностями значений:

stack = list(range(n))

Для статического анализа кода задача здесь состояла в том, чтобы понять базовый тип, возвращаемый функцией range(), и сделать вывод о возможностях, которыми обладает тип (например, поддержка операторов индекса).

Протестируйте сами и проведите анализ своего кода. Это очень быстро и бесплатно проверить на deepcode.ai.