day_6:os,os.path

读取项目目录,并统计代码行数、注释行数和空行行数

自己的想法

刚看到这个时候还没觉得多难,结果做起来发现被如何很好地判断单行注释以及多行注释给为难了很久。

又想要尽量地实现代码复用,所以翻看了一些关于类继承的说明,把自己的思路弄的更乱了。

看到句话,编程的黄金准则“先能工作,要更好,变更快”。所以把代码分成了几个部分写。

  1. 单个代码文件的读取

  2. 代码、注释和空行的判断

  3. 在逐行读取过程中加入对多行注释判断的flag

  4. 对目录内的代码文件的逐个读取

以上几点都完成后,再使用类定义和继承还有方法的改写实现代码的复用。

关于2、3两点各位都有自己的思路,因此我不多说。主要总结在解决1、2问题时使用的新的函数或是方法。


文件读取

open函数官方文档

使用open()函数读取文件时,如果读取到的行为None,那么它会将该行中的'\n', '\r', or '\r\n'都改写为'\n'后再返回;如果读取到的是' ',那么返回值最后的字符不会被转换,也就是如果是回车换行的话会返回'\n',但是整行都是空格的话是不会有'\n'的。

因此对空白行的判断是以'\n'和空格两者为准的。


目录文件的遍历

一开始时候想要自己造个轮子进行遍历,试着用了深度优先搜索,然后由于某种未知原因,程序运行的时间不敢恭维。。。不过这个过程中学习了几个新的方法

os.scandir(path)

返回一个DirEntry类,其中包含了目录内的文件和文件夹(不会向文件夹的深处继续遍历);相比于方法os.listdir()的优势在于其返回的类型可以做更多的操作,比如获取文件类型、判断其中的元素是目录还是文件等。

class os.DirEntry

其内置的方法和属性便于对文件或是文件夹进行处理

name:返回该对象的名称

path:返回该对象的绝对路径

is_file():判断该对象是否为文件,是则返回True,否则返回False

is_dir():判断该对象是否为文件目录,是则返回True,否则返回False


不造轮子了


介绍下os模块

提供了一些基于操作系统的便捷功能,因此在不同操作系统上的实现方法并不相同。
并且,官方还友情提示了以下几点:

  1. 想对文件进行处理参看open()
  2. 想对文件路径进行处理参看os.path()
  3. 想对所有文件中的所有行进行处理参看fileinput()
  4. 想要新建目录或者文件夹参看tempfile
  5. 更高级的对文件和文件目录的操作参看shuti

这是我用到的os.walk(path, topdown=True, onerror=None, followlinks=False)

由path开始进行遍历,广度优先,对每个文件夹(包括根目录)都会返回一个三元的tuple,其中包含(dirpath, dirnames , filenames)

参数中的topdown是一个决定优先生成根目录的tuple还是优先生成子目录的tuple的参数;为True即自顶向下,为False则自向上。


os.path模块

提供了一些对路径进行处理的函数

os.path.join(path, *paths):将两个参数智能地合成一个可用的路径,每个参数之间都会添加一个目录分隔符

os.path.dirname(path):返回路径下的文件夹名称

os.path.exists(path):若该路径存在或指向一个文件,返回True

os.path.getsize(path):返回路径指向对象的大小,以bits为单位

os.path.isfile(path):当路径指向的文件存在时返回True

os.path.isdir(path):当路径指向的目录存在时返回True

os.path.split(path):将path分为head和tail两个部分,其中tail为path的最后一个内容,head则是其余的所有内容


放上自己的代码

emmmm,发现漏了统计文件数目了,不过这个的实现并不困难。

import os


class Project:
    def __init__(self, direct, suffix, one_comment_symbol, inline_comment_symbol, long_comment_symbol):
        self.direct = direct
        self.suffix = suffix
        self.one_comment_symbol = one_comment_symbol
        self.inline_comment_symbol = inline_comment_symbol
        self.long_comment_symbol = long_comment_symbol
        self.codes, self.comments, self.blanks, self.project_files = self.project_check()

    @staticmethod
    def is_blank(line):
        if line == '' or line == '\n':
            return True
        else:
            return False

    def is_codes(self, line):
        if line == '' or line == '\n':
            return False
        if line.startswith(self.one_comment_symbol) or line.startswith(self.long_comment_symbol):
            return False
        if line == ' ' or line == '\n':
            return False
        else:
            return True

    def is_comment(self, line):
        beg, end, flag = False, False, False
        if line.startswith(self.long_comment_symbol):
            beg = True
        if line.endswith(self.long_comment_symbol):
            end = True
        if beg and end:
            flag = True
        if line == self.long_comment_symbol:
            flag = True
        if line.startswith(self.one_comment_symbol) or self.inline_comment_symbol in line:
            flag = True
        return flag

    def file_check(self, path, codecount=0, blankcount=0, commentcount=0):
        with open(path, encoding='utf-8') as f:
            long_comment_flag = False
            for line in f:
                line = line.strip()
                blank_flag = self.is_blank(line)
                code_flag = self.is_codes(line)
                comment_flag = self.is_comment(line)
                if long_comment_flag:  # 多行注释时只需考虑注释何时结束
                    if line == self.long_comment_symbol:
                        long_comment_flag = False
                    commentcount += 1
                else:  # 非多行注释时考虑多行注释是否开始,是否是单行注释,是否是代码段,是否是空行
                    if line == self.long_comment_symbol:
                        long_comment_flag = True
                    if comment_flag:
                        commentcount += 1
                    if code_flag:
                        codecount += 1
                    if blank_flag:
                        blankcount += 1
        return codecount, commentcount, blankcount

    def project_check(self):
        codes = 0
        comments = 0
        blanks = 0
        project_files = dict()
        for dirpath, direc, files in os.walk(self.direct):
            for file in files:
                if self.suffix in file.split('.'):
                    file_path = os.path.join(dirpath, file)
                    code, comment, blank = self.file_check(file_path)
                    codes += code
                    comments += comment
                    blanks += blank
                    project_files.setdefault(file, [code, comment, blank])  # 在project中若出现同名文件则会有问题
        return codes, comments, blanks, project_files

    def file_view(self, filename):
        file = self.project_files[filename]
        print(filename + ':' + '\n' +
              'code' + str(file[0]) + ' ' + 'comment' + str(file[1]) + ' ' + 'blank' + str(file[2]))


class Pyproject(Project):
    def __init__(self, direct, suffix='py', one_comment_symbol='#', inline_comment_symbol='  # ', long_comment_symbol="'''"):
        super(Pyproject, self).__init__(direct, suffix, one_comment_symbol, inline_comment_symbol, long_comment_symbol)

    def is_codes(self, line):
        Project.is_codes(self, line)
        # super(Pyproject, self).is_codes(line)

    def is_comment(self, line):
        Project.is_comment(self, line)
        # super(Pyproject, self).is_comment(line)


project = Project('D:\python', suffix='py', one_comment_symbol='#', inline_comment_symbol='  # ', long_comment_symbol="'''")
print(project.codes, project.comments, project.blanks)
project.file_view('day_6.py')
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容