Подсчитайте строки кода в каталоге с помощью Python

У меня есть проект, строки кода которого я хочу подсчитать. Можно ли с помощью Python подсчитать все строки кода в каталоге файлов, содержащем проект?


person Daniel    schedule 23.07.2016    source источник
comment
Используйте os.walk для перемещения по файлам и подкаталогам, используйте < a href="https://docs.python.org/3/library/stdtypes.html#str.endswith" rel="nofollow noreferrer">endswith для фильтрации файлов, которые вы хотите подсчитать, open каждый файл и используйте sum(1 for line in f) для подсчета строк, агрегируйте все подсчеты строк файла.   -  person wwii    schedule 23.07.2016
comment
Встроенная утилита wc, вероятно, заслуживает упоминания здесь, несмотря на то, что она не написана на Python. wc -l имя файла вернет количество строк в имени файла намного быстрее, чем методы чистого Python, предложенные в ответах.   -  person John    schedule 28.05.2019


Ответы (7)


Вот функция, которую я написал для подсчета всех строк кода в пакете Python и вывода информативного вывода. Он будет считать все строки во всех .py

import os

def countlines(start, lines=0, header=True, begin_start=None):
    if header:
        print('{:>10} |{:>10} | {:<20}'.format('ADDED', 'TOTAL', 'FILE'))
        print('{:->11}|{:->11}|{:->20}'.format('', '', ''))

    for thing in os.listdir(start):
        thing = os.path.join(start, thing)
        if os.path.isfile(thing):
            if thing.endswith('.py'):
                with open(thing, 'r') as f:
                    newlines = f.readlines()
                    newlines = len(newlines)
                    lines += newlines

                    if begin_start is not None:
                        reldir_of_thing = '.' + thing.replace(begin_start, '')
                    else:
                        reldir_of_thing = '.' + thing.replace(start, '')

                    print('{:>10} |{:>10} | {:<20}'.format(
                            newlines, lines, reldir_of_thing))


    for thing in os.listdir(start):
        thing = os.path.join(start, thing)
        if os.path.isdir(thing):
            lines = countlines(thing, lines, header=False, begin_start=start)

    return lines

Чтобы использовать его, просто укажите каталог, в котором вы хотите начать. Например, чтобы подсчитать строки кода в каком-то пакете foo:

countlines(r'...\foo')

Что выведет что-то вроде:

     ADDED |     TOTAL | FILE               
-----------|-----------|--------------------
        5  |        5  | .\__init__.py       
       539 |       578 | .\bar.py          
       558 |      1136 | .\baz\qux.py         
person Bryce93    schedule 20.09.2017
comment
import io и попробуйте использовать io.open вместо open, если у кого-то есть проблемы с использованием python2 - person MrMesees; 07.10.2018
comment
Ах, хорошо, это было неочевидно ... сначала я хотел знать, что такое «ДОБАВЛЕНО»? Затем я понял, что ваше «ИТОГО» на самом деле является совокупным количеством «ДОБАВЛЕННЫХ». - person Jeach; 23.09.2019
comment
но 5+539!=578 - person nmz787; 13.03.2020

pygount отобразит все файлы в папке, каждый с количеством строк кода (исключая документацию)

https://pypi.org/project/pygount/

pip install pygount

Чтобы просмотреть результаты для текущего каталога, выполните:

pygount ~/path_to_directory
person Vilmar Rafael    schedule 11.01.2019
comment
Этой программе удается заполнить мои 16 ГБ оперативной памяти и, в свою очередь, вывести мой компьютер из строя. - person Philipp; 29.10.2020
comment
Удалось заставить его работать, исключив мои venv и рассматривая только файлы .py с: pygount --suffix=py --folders-to-skip=venv,venv2 . - person Philipp; 29.10.2020

В дополнение к ответу pygount они просто добавили опцию --format=summary, чтобы получить общее количество строк в разных типах файлов в каталоге.

pygount --format=summary ./your-directory

может вывести что-то вроде

  Language     Code    %     Comment    %
-------------  ----  ------  -------  ------
XML            1668   48.56       10    0.99
Python          746   21.72      150   14.90
TeX             725   21.11       57    5.66
HTML            191    5.56        0    0.00
markdown         58    1.69        0    0.00
JSON             37    1.08        0    0.00
INI              10    0.29        0    0.00
Text              0    0.00      790   78.45
__duplicate__     0    0.00        0    0.00
-------------  ----  ------  -------  ------
Sum total      3435             1007
person Community    schedule 16.03.2020

Это немного похоже на домашнее задание :-) - тем не менее, это полезное упражнение, и форматирование Bryce93 приятное. Я думаю, что многие вряд ли будут использовать Python для этого, учитывая, что это можно сделать быстро с помощью нескольких команд оболочки, например:

cat $(find . -name "*.py") | grep -E -v '^\s*$|^\s*#' | wc -l

Обратите внимание, что ни одно из этих решений не учитывает многострочные (''') комментарии.

person JP Lodine    schedule 28.05.2019
comment
Короткий и достаточно хороший для меня! Если кто-то вроде меня не хочет включать, вы можете вместо этого использовать cat *.py на первом шаге. - person Alex Telon; 05.11.2019

from os import listdir
from os.path import isfile, join
def countLinesInPath(path,directory):
    count=0
    for line in open(join(directory,path), encoding="utf8"):
        count+=1
    return count
def countLines(paths,directory):
    count=0
    for path in paths:
        count=count+countLinesInPath(path,directory)
    return count
def getPaths(directory):
    return [f for f in listdir(directory) if isfile(join(directory, f))]
def countIn(directory):
    return countLines(getPaths(directory),directory)

Чтобы подсчитать все строки кода в файлах в каталоге, вызовите функцию «countIn», передав каталог в качестве параметра.

person Daniel    schedule 23.07.2016
comment
Разве у python уже нет len(file.readlines())? И это только один из известных мне способов - person OneCricketeer; 23.07.2016
comment
Да, я думаю, что это тоже может сработать, хотя это не требует много кода. - person Daniel; 23.07.2016

Это получено из ответа Дэниела (хотя и достаточно реорганизовано, чтобы это не было очевидно). Этот не выполняет рекурсию по подкаталогам, чего я и хотел.

from os import listdir
from os.path import isfile, isdir, join
def item_line_count(path):
    if isdir(path):
        return dir_line_count(path)
    elif isfile(path):
        return len(open(path, 'rb').readlines())
    else:
        return 0
def dir_line_count(dir):
    return sum(map(lambda item: item_line_count(join(dir, item)), listdir(dir)))
person Daniel Weaver    schedule 21.03.2018

На основе ответа Bryce93 с параметром code_only для исключения комментариев, строк документации и пустых строк из подсчета строк:

import os

def countlines(rootdir, total_lines=0, header=True, begin_start=None,
               code_only=True):
    def _get_new_lines(source):
        total = len(source)
        i = 0
        while i < len(source):
            line = source[i]
            trimline = line.lstrip(" ")

            if trimline.startswith('#') or trimline == '':
                total -= 1
            elif '"""' in trimline:  # docstring begin
                if trimline.count('"""') == 2:  # docstring end on same line
                    total -= 1
                    i += 1
                    continue
                doc_start = i
                i += 1
                while '"""' not in source[i]:  # docstring end
                    i += 1
                doc_end = i
                total -= (doc_end - doc_start + 1)
            i += 1
        return total

    if header:
        print('{:>10} |{:>10} | {:<20}'.format('ADDED', 'TOTAL', 'FILE'))
        print('{:->11}|{:->11}|{:->20}'.format('', '', ''))

    for name in os.listdir(rootdir):
        file = os.path.join(rootdir, name)
        if os.path.isfile(file) and file.endswith('.py'):
            with open(file, 'r') as f:
                source = f.readlines()

            if code_only:
                new_lines = _get_new_lines(source)
            else:
                new_lines = len(source)
            total_lines += new_lines

            if begin_start is not None:
                reldir_of_file = '.' + file.replace(begin_start, '')
            else:
                reldir_of_file = '.' + file.replace(rootdir, '')

            print('{:>10} |{:>10} | {:<20}'.format(
                    new_lines, total_lines, reldir_of_file))

    for file in os.listdir(rootdir):
        file = os.path.join(rootdir, file)
        if os.path.isdir(file):
            total_lines = countlines(file, total_lines, header=False,
                                     begin_start=rootdir, code_only=code_only)
    return total_lines
person OverLordGoldDragon    schedule 20.06.2020