使用PrettyTable在目录中打印出Python文件的详细信息

如何解决使用PrettyTable在目录中打印出Python文件的详细信息

我正在尝试编写一个FileAnalyzer类,该类将在目录中搜索Python文件,并以prettytable的形式提供每个Python文件的详细信息。我对每个Python文件中的类,函数,行和字符的数量感兴趣。

学习OOP的绳索...这是我到目前为止的代码

class FileAnalyzer:
    def __init__(self,directory: str) -> None:
        """
        The files_summary attribute stores the summarized data for each Python file in the specified directory.
        """
        self.directory: str = os.listdir(directory) #Directory to be scanned

        self.analyze_files()  # summarize the python files data

        self.files_summary: Dict[str,Dict[str,int]] = {
            dir: {
                'Number of Classes': cls,'Number of Functions': funccount,'Number of Lines of Code': codelines,'Number of Characters': characters
            }
        }

    def analyze_files(self) -> None:
        """
        This method scans a directory for python files. For every python file,it determines the number of classes,functions,lines of code,and characters. The count for each one is returned in a tuple.
        """
        for dir in self.directory:
            if dir.endswith('.py'):  # Check for python files
                with open(dir,"r") as pyfile:

                    cls = 0  # Initialize classes count
                    for line in pyfile:
                        if line.startswith('Class'):
                            cls += 1

                    funccount = 0  # Initialize function count
                    for line in pyfile:
                        if line.startswith('def'):
                            funccount += 1

                    #Get number of lines of code
                    i = -1 #Account for empty files
                    for i,line in enumerate(pyfile):
                        pass

                    codelines = i + 1

                    #Get number of characters
                    characters = 0
                    characters += sum(len(line) for line in pyfile)

        return [cls,funccount,codelines,characters]


    def pretty_print(self) -> None:
        """
        This method creates a table with the desired counts from the Python files using the prettytable module.
        """
        pt: prettytable = prettytable(field_names=['# of Classes','# of Functions','# Lines of Code (Excluding Comments)','# of characters in file (Including Comments)'])

        for cls,characters in self.files_summary():
            pt.add_row([cls,characters])

        print(pt)

FileAnalyzer('/path/to/directory/withpythonfiles')

当我尝试运行代码时,当前出现NameError: name 'cls' is not defined错误。在self.analyze_files()调用__init__不足以将返回的值传递到__init__中吗?理想情况下,对于

的python文件
def func1():
    pass

def func2():
    pass

class Foo:
    def __init__(self):
        pass

class Bar:
    def __init__(self):
        pass


if __name__ == "__main__":
    main()

prettytable会告诉我,有2个类,4个函数,25行和270个字符。对于以下文件

definitely not function

This is def not a function def 

prettytable会告诉我该文件具有0个功能。我希望self.analyze_files()将汇总数据填充到self.files_summary中,而无需将任何其他参数传递给analyze_files()。同样,将数据从files_summary传递到pretty_print,而没有单独的参数传递给pretty_print

编辑:

self.files_summary: Dict[str,int]] = {
            dir: {
                'Number of Classes': self.analyze_files()[0],'Number of Functions': self.analyze_files()[1],'Number of Lines of Code': self.analyze_files()[2],'Number of Characters': self.analyze_files()[3]
            }
        }

抑制了错误,但是

        for self.analyze_files()[0],self.analyze_files()[1],self.analyze_files()[2],self.analyze_files()[3] in self.files_summary():
            pt.add_row([self.analyze_files()[0],self.analyze_files()[3]])

        return pt
当我打电话给FileAnalyzer时,pretty_print中的

没有任何作用...

解决方法

这个问题有点广泛,因此很难提供一个简洁的答案。您在评论中说:

如果我在 init 中执行类似[cls,funccount,codelines,characters] = self.analyze_files()的操作,似乎也无法正确引用返回的值

虽然在样式上有些奇怪,但实际上这是非常好的语法。如果您的__init__方法看起来像这样,它将运行无错误:

    def __init__(self,directory: str) -> None:
        """
        The files_summary attribute stores the summarized data for each Python file in the specified directory.
        """
        self.directory: str = os.listdir(directory) #Directory to be scanned

        [cls,characters] = self.analyze_files()

        self.files_summary: Dict[str,Dict[str,int]] = {
            dir: {
                'Number of Classes': cls,'Number of Functions': funccount,'Number of Lines of Code': codelines,'Number of Characters': characters
            }
        }

但是,有许多问题。首先,在上述方法中,您使用的是变量名dir,但作用域中没有此类变量。不幸的是,dir也是Python内置函数的名称。如果在此部分代码后插入breakpoint()并打印self.files_summary的值,您会看到它看起来像这样:

{<built-in function dir>: {'Number of Classes': 0,'Number of Functions': 0,'Number of Lines of Code': 0,'Number of Characters': 0}}

通常,切勿选择遮盖Python内置变量的变量名,因为它可能导致意外的问题且难以调试。如果您使用具有Python语法高亮显示支持的体面的编辑器,则会看到这些内置组件被调出,从而可以避免出现此错误。

认为而不是dir,而是self.directory(或者只是directory,因为该变量在此范围内)。


但是还有另一个问题。

在您的pretty_print方法中,您正尝试调用 self.files_summary,如下所示:

for cls,characters in self.files_summary():

但是self.files_summary不是函数,不能调用。这是一个字典,这也意味着在这样的for循环中使用它实际上没有任何意义。由于您在__init__中进行设置的方式,因此只有一个键。

如果我是你,我将把该程序分解为各个部分,并在尝试将各个部分捆绑在一起之前先使其正常工作。充分利用交互式Python提示符和调试器;在代码中使用breakpoint()语句来检查变量的内容,然后再使用它们。


如果我要重写您的代码,则可能会执行以下操作:

import os
import re

from prettytable import PrettyTable

re_class = re.compile(r'class')
re_def = re.compile(r'\s*def')


class FileAnalyzer:
    def __init__(self,path: str) -> None:
        self.path = path
        self.analyze_files()

    def analyze_files(self) -> None:
        self.files = []

        for entry in os.listdir(self.path):
            if not entry.endswith('.py'):
                continue

            with open(entry,"r") as pyfile:

                cls = 0
                funccount = 0
                codelines = 0
                characters = 0

                for line in pyfile:
                    codelines += 1
                    characters += len(line)

                    if re_class.match(line):
                        cls += 1
                    elif re_def.match(line):
                        funccount += 1

            self.files.append((entry,cls,characters))

    def pretty_print(self) -> None:
        pt: PrettyTable = PrettyTable(
            field_names=['Filename','# of Classes','# of Functions','# Lines of Code (Excluding Comments)','# of characters in file (Including Comments)'])

        for path,characters in self.files:
            pt.add_row([path,characters])

        print(pt)


x = FileAnalyzer('.')
x.pretty_print()

请注意,我已经在您的for函数中删除了多个analyze_files循环;没有理由多次遍历每个文件。这将建立一个名为files的实例变量,它是结果列表。 pretty_print方法只是遍历此列表。

如果我在Python暂存目录中运行上述代码,则会得到:

+--------------------------+--------------+----------------+--------------------------------------+----------------------------------------------+
|         Filename         | # of Classes | # of Functions | # Lines of Code (Excluding Comments) | # of characters in file (Including Comments) |
+--------------------------+--------------+----------------+--------------------------------------+----------------------------------------------+
|       yamltest.py        |      0       |       0        |                  30                  |                     605                      |
|       analyzer.py        |      1       |       3        |                  53                  |                     1467                     |
|         quake.py         |      0       |       0        |                  37                  |                     1035                     |
| test_compute_examples.py |      1       |       1        |                  10                  |                     264                      |
|   compute_examples.py    |      1       |       1        |                  4                   |                      82                      |
+--------------------------+--------------+----------------+--------------------------------------+----------------------------------------------+

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?