Это домашнее задание из школы, которое я делал ...
Поэтому меня попросили отсканировать данный каталог и найти в нем все файлы .py, а также подсчитать заданные атрибуты, которые являются классами и функциями.(включая методы в классах), определенные в файле, и общее количество строк и символов для каждого файла.И распечатайте все данные в таблице на терминале.
Чтобы напечатать таблицу, мой лектор предложил использовать пакет под названием prettytable , хотя для меня это не совсем таквсе.
Я хочу использовать панд .
Причина проста: для каждого файла насчитывается 4 атрибута -> здесь естественно вызывается nested-dict.И pandas.DataFrame на 100% идеально подходит для записи вложенных диктов.
Сканирование и суммирование - это простая часть, что на самом деле меня зацепило: как сделать контейнер данных гибким и масштабируемым.
Встроенный dict не может инициализироваться с 4 существующими парами ключ-значение, поэтому я создаю класс CountAttr (MutableMapping) и использую другой класс FileCounter для создания и подсчета каждого атрибута для каждого файла.
Однако pandas.DataFrame распознает только первый слой этого объекта, похожего на dict.И я прочитал исходные файлы DataFrame и Series, все еще не в состоянии понять, как решить эту проблему.
Итак, мой вопрос,
как заставить pandas.DataFrame / Series извлекать данные из словаря, значения которого являются объектами типа dict?
PS IЯ открыт для каждого совета по следующему коду, стилю кодирования, способу реализации, всему.Очень ценю!
from collections.abc import MutableMapping
from collections import defaultdict
import pandas as pd
import os
class CounterAttr(MutableMapping):
""" Initialize a dictionary with 4 keys whose values are all 0,
keys:value
- 'class': 0
- 'function': 0
- 'line': 0
- 'char': 0
interfaces to get and set these attributes """
def __init__(self):
""" Initially there are 4 attributes in the storage"""
# key: counted attributes | value: counting number
self.__dict__ = {'class': 0, 'function': 0, 'line': 0, 'char': 0}
def __getitem__(self, key):
if key in self.__dict__:
return self.__dict__[key]
else:
raise KeyError
def get(self, key, defaut = None):
if key in self.__dict__:
return self.__dict__[key]
else:
return defaut
def __setitem__(self, key, value):
self.__dict__[key] = value
def __delitem__(self, key):
del self.__dict__[key]
def __len__(self):
return len(self.__dict__)
def __iter__(self):
return iter(self.__dict__)
def get_all(self):
""" return a copy of the self._storagem, in case the internal data got polluted"""
copy = self.__dict__.copy()
return copy
def to_dict(self):
return self.__dict__
def __repr__(self):
return '{0.__class__.__name__}()'.format(self)
class FileCounter(MutableMapping):
""" Discribe the object the store all the counters for all .py files
Attributes:
-
"""
def __init__(self):
self._storage = dict()
def __setitem__(self, key, value = CounterAttr()):
if key not in self._storage.keys():
self._storage[key] = value
else:
print("Attribute exist!")
def __getitem__(self, key):
if key in self._storage.keys():
return self._storage[key]
else:
self._storage[key] = CounterAttr()
def __delitem__(self, key):
del self._storage[key]
def __len__(self):
return len(self._storage)
def __iter__(self):
return iter(self._storage)
def scan_summerize_pyfile(directory, give_me_dict = False):
""" Scan the passing directory, find all .py file, count the classes, funcs, lines, chars in each file
and print out with a table
"""
file_counter = FileCounter()
if os.path.isdir(directory): # if the given directory is a valid one
os.chdir(directory) # change the CWD
print("\nThe current working directory is {}\n".format(os.getcwd()))
file_lst = os.listdir(directory) # get all files in the CWD
for a_file in file_lst: # traverse the list and find all pyfiles
if a_file.endswith(".py"):
file_counter[a_file]
try:
open_file = open(a_file, 'r')
except FileNotFoundError:
print("File {0} can't be opened!".format(a_file))
else:
with open_file:
for line in open_file:
if line.lstrip().startswith("class"): # count the classes
file_counter[a_file]['class'] += 1
if line.lstrip().startswith("def"): # count the functions
file_counter[a_file]['function'] += 1
file_counter[a_file]['line'] += 1 # count the lines
file_counter[a_file]['char'] += len(line) # count the chars, no whitespace
else:
print("The directory", directory, "is not existed.\nI'm sorry, program ends.")
return file_counter
# Haven't had the pandas codes part yet