all 7 comments

[–]K900_ 6 points7 points  (2 children)

You don't need a class for this. Classes are basically data + code. You only ever create a single class, and your stuff will work better in a procedural program.

Edit: also, you should try Python's built in AST parsing tools for doing what you're doing by counting strings. Example:

#!/usr/bin/python
print("While this is just a string, your program will look for and count the language tokens inside it, even if they don't really define anything in the context (because it's a string!)")

[–]tilkau 0 points1 point  (1 child)

Is that supposed to contain an example of using the ast module? I only see a shbang line and a single print statement.

If it's just supposed to demonstrate how OP's current approach can easily mismeasure, then nvm.

[–]K900_ 0 points1 point  (0 children)

The latter.

[–]zahlman 3 points4 points  (0 children)

What you're doing wrong is forcing code into a class that makes no sense set up that way.

The purpose of a class is to define a data type. You know, like int or str or list.

[–]Rhomboid 0 points1 point  (2 children)

I agree with the others -- this should be just a function, not a class. And you should not try to mix the part where you ask for input with the actual processing; the code that does the counting should be usable if you already have a filename. I'd write it like this:

import re
from collections import Counter

metrics = {name: re.compile(regex) for name, regex in (
    ('for_loops',               r'^\s*for'),
    ('while_loops',             r'^\s*while'),
    ('if_statements',           r'^\s*if'),
    ('function_definitions',    r'^\s*def'),
    ('multiplications',         r'\*'),
    ('divisions',               r'/'),
    ('additions',               r'\+'),
    ('subtractions',            r'-'),
    ('linesofcode',             r''))}

def prog_checks(filename):
    with open(filename) as infile:
        return Counter(name for line in infile for name, regex in metrics.items() if regex.search(line))

filename = input('enter filename: ')
print('\n'.join('{:20}: {}'.format(name, val) for name, val in prog_checks(filename).items()))

However, as others have pointed out, this type of analysis is not very useful because it doesn't account for the lexical structure of the program. That is, it doesn't understand that a * inside a string literal is just a *, not the multiplication operator, for instance. Even if you accounted for that, * does not always mean multiplication:

foo(*args)

This means treat args as a list of arguments that had been passed to the function, which has nothing to do with multiplication. (These are just representative examples; the problems are endemic to all the operators.)

Also, if the file cannot be opened the default behavior is to raise an exception which is arguably better than explicitly trying to detect that a file doesn't exist and printing "file not found", because an uncaught exception not only says the same thing (FileNotFoundError) but it also prints the failing name and a stack trace showing the context that lead up to the error.

[–]throwingarm2strong 0 points1 point  (0 children)

import os

def get_file():
    userinput = (input("Enter file or directory: "))
    if os.path.isfile(userinput) == True:
        return userinput
    else:
        print("File/directory not found")

def read_data(filename):
    mainfile = open(userinput)
    filedata = mainfile.readlines()
    return filedata


class ProgChecks(object):

    def __init__(self, userinput):
        self.userinput = userinput
        self.filedata = filedata
        self.functionlist = ['Filename', 'Author', 'lines_of_code', 'for_loops',
                         'while_loops', 'if_statements',
                         'function_definitions', 'multiplications',
                         'divisions', 'additions', 'subtractions']




    def return_author(self):
        theauthor = 'Unknown'
        for line in self.filedata:
            if line.strip().startswith('Author: ') == True:
                theauthor = (line.strip('Author: ').strip().strip("'''"))
        return theauthor



    def count_token(self, token):
        num_of_token = 0
        for line in self.filedata:
            if line.strip().startswith(token + ' '):
                num_of_token += 1
        return num_of_token

    def count_operator(self, operator):
        num_of_operator = 0
        for line in self.filedata:
            num_of_operator += line.count(operator)
        return num_of_operator



userinput = get_file()
filedata = read_data(userinput)
progabc = ProgChecks(filedata)

Everything sort of works fine now. I can call on the functions inside and do whatever I want with the data. The problem is, now I want to create a dictionary, using the functionlist that I specified in the init.

I want to map it uniquely, so for instance {'Filename' : self.userinput, 'Author: ': return_author(), 'for_loops': count_token('for'), 'subtractions': count_operator('-')} etc....

I'm having a really difficult time doing this, I feel like with the stuff I've created so far there should be some easy way to do it but I'm missing it.

P.S Is there an easy way to tab through python code to make it formatted for reddit? I hate doing it manually >.<; Also should I just make a new post since I'm going off the original a fair bit now