Вы преподаете программирование, и вы находитесь в компьютерной лаборатории класса, помогая студентам. Приближается большой срок, и становится очень поздно. Студент просит о помощи. Почему его код не проходит все необходимые тестовые случаи?

Вы просите его объяснить вам свою логику. Вы не признаете его подход к проблеме. Это может быть новая идея или фатально ошибочная.

Вы посмотрите на его решение и тестовые случаи, в которых оно не работает. Его код написан нечетко. Вы не можете сказать, почему его код возвращает неправильные ответы.

Это задание существует уже много лет. Вы задаетесь вопросом, успешно ли кто-нибудь еще когда-либо реализовывал этот подход. Если бы вы только могли прочитать тысячи предыдущих студенческих решений, которые хранятся в вашей файловой системе!

Вы начинаете случайным образом распечатывать решения и просматривать их, например, эти пять примеров, которые должны итеративно возводить в степень аргумент «база» к аргументу «эксп»:

def iterPower(base, exp):
    '''
    base: int or float.
    exp: int >= 0
 
    returns: int or float, base^exp
    '''
    # Your code here
    res=1.
    while exp>0:
        exp-=1
        res=res*base
    return res
def iterPower(base, exp):
    if exp == 0:
        return 1
    ans = base
    while exp >1 :
        ans *= base
        print base
        exp -= 1
        print exp
    print ans
    return ans
def iterPower(base, exp):
    '''
    base: int or float.
    exp: int >= 0
 
    returns: int or float, base^exp
    '''
    # Your code here
    result = 1
    while exp > 0:
        result *=base
        exp -= 1
    return result
def iterPower(base, exp):
    '''
    base: int or float.
    exp: int >= 0
 
    returns: int or float, base^exp
    '''
    ans = base
    if (exp == 0):
        return round(base/base, 4)
    else:
        for n in range(exp-1):
            ans *= base
        return round(ans, 4)
def iterPower(base, exp):
    result = base
    if exp==0:
        return 1
    if exp==1:
        return result
    while exp > 1:
        result *= base
        exp -= 1
    return result

Вы не можете прочитать тысячи решений за разумное время. Итак, что бы вы хотели прочитать, чтобы максимально приблизиться к реальности?

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

Analysis Pipeline Pseudocode
1 A. Remove comments from all solutions
  B. Remove solutions that are now duplicates

Вы найдете другое решение, идентичное первому, но с другими вариантами форматирования, такими как дополнительные пробелы внутри и между строками. Вы решаете, что вам не нужно читать и это. Вы добавляете еще один шаг в конвейер анализа.

Analysis Pipeline Pseudocode (cont'd)
2 A. Reformat all solutions, so they all have the same formatting
  B. Remove solutions that are now duplicates

Вы найдете другое решение, идентичное первому, но с другими именами переменных. Вы решаете, что вам не нужно читать и это. Вы делаете паузу.

Имена переменных очень важны для удобочитаемости кода. Вы не хотите застрять в чтении студенческого кода с именами переменных «temp1», «temp2», «temp3»… Как выбрать, какое из двух решений, которые отличаются только именами переменных, читать?

Вы не выбираете. Вы позволяете студентам голосовать и молитесь, чтобы мудрость толпы решила это за вас. И студенты уже проголосовали. Они уже представили решения со своим собственным выбором имен переменных, независимо от всех остальных. Вы можете вычислить наиболее популярное имя, данное каждой переменной, и использовать эти имена для переменных в решении, которое вы, учитель, должны прочитать.

Как узнать, проголосовали ли два студента за одно и то же имя переменной? Как узнать, что переменная «i» в одном решении «та же самая», что и переменная «x» в другом решении? Что вообще означает «одна и та же переменная в двух разных решениях»?

Вероятно, вы могли бы вручную пометить переменные в решениях учащихся как «одинаковые», если они играют одну и ту же «роль», например, индексируют один и тот же массив или накапливают один и тот же результат. Как вы автоматизируете пометку переменных как «одинаковых» во всех решениях учащихся?

Вы выполняете все решения в тестовом примере, например:

iterPower(5,3)

Переменные в каждом решении принимают последовательность значений. Вы можете убедиться в этом сами, воспользовавшись Онлайн-репетитором Python. По мере прохождения каждого решения вы замечаете, что переменные, играющие одну и ту же роль в каждой программе, принимают одинаковую последовательность значений во время выполнения этого тестового примера.

Например, переменная, которая принимает последовательность

1, 5, 25, 125

появляется в большинстве решений, а точнее в 3081 из 3842. Его наиболее распространенное название — «результат», но студенты (со всего мира) дают ему и другие названия: «выник», «выход», «итого», «ответ», «аккум», «число» и «множество». назвать несколько.

Это консервативное понятие «одинакового» в некоторых случаях, когда две переменные имеют одинаковую роль, но различаются своим первым или последним значением. Это самонадеянное понятие «одинаково», когда два логических флага переключаются с «ложь» на «истина» в разные моменты выполнения, захватывая разную информацию, но при этом принимая одну и ту же последовательность значений — «ложь» на «истина». Но на практике он хорошо работает с имеющимися у вас вводными программами на Python, поэтому вы работаете с ним как с несовершенным, но хорошим началом.

Вы найдете все уникальные последовательности значений, которые принимают переменные в этих тысячах студенческих решений. Вы называете их «общие переменные». Вы отслеживаете все имена, которые студенты когда-либо давали им. Вы определяете самый популярный.

Если две разные общие переменные чаще всего называются «i», то вы позволяете общей переменной, которая появляется в большинстве решений учащихся, называться «i», а другую, менее популярную общую переменную, вы называете «i2». Теперь каждое имя переменной соответствует отдельной последовательности значений во время выполнения тестовых случаев.

Затем вы добавляете новый шаг в конвейер:

Analysis Pipeline Pseudocode (cont'd)
3 A. Rename all variables in all solutions to their most popular names
  B. Remove solutions that are now duplicates

Эти два решения, которые отличаются только именами переменных:

def iterPower(mybase, exp):
    res=1
    while exp>0:
        exp-=1
        res=res*mybase
    return res
def iterPower(base, exp):
    result=1
    while exp>0:
        exp-=1
        result=result*base
    return result

… стать идентичными.

Имена переменных теперь имеют семантическую ценность, и во всех решениях есть общий словарь. Переменная «x» в одном решении ведет себя в тестовых примерах так же, как переменная «x» в другом решении.

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

Вы начинаете просматривать этот сокращенный набор. Два решения имеют одинаковый набор строк, но порядок операторов в цикле меняется местами:

def iterPower(base, exp):
    result=1
    while exp>0:
        exp-=1
        result=result*base
    return result
def iterPower(base, exp):
    result=1
    while exp>0:
        result=result*base
        exp-=1
    return result

Вы понимаете, что изменение порядка операторов не повлияло на значения переменных во время выполнения, поэтому это не должно иметь значения. Вам не нужно читать оба. Вы добавляете последний шаг в конвейер анализа:

Analysis Pipeline Pseudocode (cont'd)
4 A. Find all the solutions that only differ by statement order
  B. Keep the solution with the most popular statement order
  C. Remove all the others

Теперь, когда вы читаете решение из набора оставшихся решений, это не обязательно решение, написанное каким-то конкретным студентом, но оно представляет собой решения сотен или тысяч студентов. Вы подсчитываете, сколько учащихся представляет каждое решение. Вы читаете их, от «наибольшего» до «наименьшего», бегло просматривая, потому что все они используют один и тот же набор имен переменных, в интерфейсе, который выделяет различия между решениями, когда вы читаете.

Это один из способов прочитать тысячи решений Python одновременно.

Это работа Ришаба Сингха, Филипа Гуо, Джереми Скотта, Роба Миллера и меня с дополнительной помощью Стейси Терман, которая расширила OverCode для обработки неверных решений (здесь не обсуждается). Для получения дополнительной информации перейдите на нашу домашнюю страницу проекта или в репозиторий github.