Python — комментарии в начале строк

Я унаследовал некоторый код Python 2.7, который закомментировал участки кода в начале каждой строки, что сводит меня с ума. Код разделен на несколько файлов и составляет> 50 тыс. строк, поэтому я ищу способ автоматически исправить это. Не все комментарии находятся в начале строк, но некоторые есть. Я пробовал переопределить и autopep8, но ни один из них не решил эту проблему. Вот пример:

def test_function():
    a = 1

# There are comments that are not indented!
# Usually with commented out code like this:
#    c = 5
#    if c > a:
#        a = c

    b = 5
    return a*b
print(test_function())

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

def test_function():
    a = 1

    # There are comments that are not indented!
    # Usually with commented out code like this:
    # c = 5
    # if c > a:
    #     a = c

    b = 5
    return a*b
print(test_function())

Кто-нибудь знает, есть ли уже какая-то библиотека, которая может это сделать, прежде чем я пойду и попытаюсь что-то создать самостоятельно?

если вы удалите только # в начале, отступ будет в порядке с вашим первым примером. Если вы сделаете это во втором примере, это уничтожит программу.

Jean-François Fabre 26.01.2019 18:20

Это больше похоже на заброшенный код. Также похоже, что кто-то не использовал контроль версий. Покрывается ли он тестами?

progmatico 26.01.2019 18:46

Во втором примере вы должны удалить «#» из строк кода (удалить # и пробел). Это поддерживает совместимость с pep8, которой я обычно придерживаюсь. Удалить «#» в начале строки так же просто, как и «#».

Scott B 26.01.2019 21:31

Да, это заброшенный код, и я планирую его очистить, но мне нужно попытаться понять, почему код был заброшен, и очистить его (в свое время). Код сейчас не в лучшей форме, и он не контролируется версиями. Я также планирую переместить его в репозиторий git, когда смогу.

Scott B 26.01.2019 21:31
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
4
106
2

Ответы 2

Я собрал несколько наивный скрипт awk, который должен уметь делать отступы для ваших комментариев:

#!/usr/bin/gawk -f
BEGIN{
    last_indent=0
}

{
    indent=match($0, /[^ ]/) - 1
    if (indent < 0) indent = 0
    comment=0
}

/^#/{
    comment=1
    if (last_indent > 0) {
        indent_str = sprintf("%*s", last_indent, " ")
        $0 = indent_str $0
    }
}

{
    print
    if (length($0) && ! comment) last_indent=indent
}

Запуск с помощью:

$ cat src.py | ./reindent.awk

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

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

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


В простом случае, например, это может даже привести к отступу кода в комментариях:

#!/usr/bin/gawk -f
BEGIN{
    last_indent=0
    commented_code_indent = 0
}

{
    indent=match($0, /[^ ]/) - 1
    if (indent < 0) indent = 0
    comment=0
}

/^#/{
    comment=1
    if (last_indent > 0) {
        indent_str = sprintf("%*s", last_indent, " ")
    stripped = length($0)
    sub(/#  +/, "# ")
    stripped -= length($0)
    if (stripped > 0 && ! commented_code_indent) commented_code_indent = stripped
    if (commented_code_indent > 0) {
       indent_in_comment = stripped - commented_code_indent
       if (indent_in_comment > 0) {
           comment_indent_str = sprintf("%*s", indent_in_comment, " ")
           sub(/# /, "# " comment_indent_str)
       }
        }
    $0 = indent_str $0
    }
}

{
    print
    if (length($0) && ! comment) last_indent=indent
    if (! comment) commented_code_indent = 0
}

И да, глядя на это сейчас, мог бы быть более легкий выбор, чем awk. :)

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

Scott B 26.01.2019 21:33

Строки, начинающиеся с #, отступают так, чтобы они соответствовали тому же уровню отступа, что и следующая строка без комментариев:

import sys

def remove_excess_space(comments):
    """Remove excess whitespace after #"""
    excess = 0
    for line in comments:
        stripped = line.lstrip('#').lstrip()
        if excess == 0:
            excess = len(line) - len(stripped) - len('# ')
        if excess > 0:
            line = '#{}'.format(line[1 + excess:])
        yield line

def fix(filename):
    indentation = 0
    comments = []
    with open(filename, 'r') as f:
        for line in f:
            if line.startswith('#'):
                comments.append(line)
            else:
                stripped = line.lstrip()                
                if stripped and not stripped.startswith('#'):
                    # I'm assuming indentation is done with spaces, not tabs
                    indentation = len(line) - len(stripped)

                if comments:
                    # indent the comments using the same indenation as the next non-comment line
                    print(''.join(['{}{}'.format(' '*indentation, line)
                                   for line in remove_excess_space(comments)]), end='')
                    comments = []                    
                print(line, end='')

if __name__ == '__main__':
    filename = sys.argv[1]
    fix(filename)

Если мы назовем этот indent_comments.py, то запустим:

indent_comments.py /path/to/script.py

отпечатки

def test_function():
    a = 1

    # There are comments that are not indented!
    # Usually with commented out code like this:
    # c = 5
    # if c > a:
    #     a = c

    b = 5
    return a*b
print(test_function())

Обратите внимание, что есть крайние случаи, когда этот сценарий облажался. Например, не каждая строка, начинающаяся с #, обязательно является комментарием:

print('''\
# This is not 
    a comment
''')

станет

print('''\
    # This is not 
    a comment
''')

Спасибо, я попробую это, когда снова буду перед кодом. Спасибо и за предупреждения по угловым случаям.

Scott B 26.01.2019 21:36

Другие вопросы по теме