2
\$\begingroup\$

Here's the context: My code is meant to automate testing of OCR (Image to Text programs) for a science project which could easily be read and understood my others. The code includes sets of functions which serve different purposes. Basically, there are functions which deal with the drawing and saving of pages (drawtext(), createpage(), etc.), functions which run various OCR on an image (tesseractocr(), etc.) and a function which computes the difference between two strings (levenshtein()).

Having all these functions in main.py results, in my opinion, in a cluttered piece of code. Is it better generally to:

  1. Keep all those functions in main.py so that the entire code is in one file.
  2. Put all these functions in one functions.py file
  3. Put each set of functions in a file, resulting in a levenshtein.py, ocr.py, and pagemaker.py in addition to the main.py.

Honestly, I feel that either 2 or 3 is the choice to make, I'm just not sure. Additionally, what level of abstraction would you usually want in a main.py file? Should the file look like

import ocr, levenshtein, pagemaker
import "a few other things"
define vars, etc

for page in pages:
    correct = pagemaker.drawpage(input1,input2,(input3,input4),etc) #also saves image
    tesseract_out = ocr.tesseract("img.png")
    tesseract_dist = levenshtein.levenshtein(correct, tesseract_out)
    print(f"Tesseract Distance: {tesseract_dist}")
    #etc for other ocr

Or is that too abstract? Also, is command-line argument parsing (which I didn't include above) generally in the main.py file or should you simply make a file called parseocrargs.py and run

pages, color, etc = parseocrargs.argparse(aruments grabbed earlier)

I guess the main question(s) are: Should a standalone (doesn't interact with other functions) but lengthy/ugly function go in a separate file than the other functions? Should almost all functions not be in main.py? If not, how many should be? Should main.py be extremely abstracted? If not, how abstracted should it be?

\$\endgroup\$
  • \$\begingroup\$ @Linny I posted it on StackOverflow and was told it was a better question for CodeReview \$\endgroup\$ – Theo Dec 31 '19 at 4:45
  • \$\begingroup\$ If that's the case, do you mind posting the code in question? \$\endgroup\$ – Linny Dec 31 '19 at 4:46
  • \$\begingroup\$ @Linny I can post the whole code dump in my question, is that okay? \$\endgroup\$ – Theo Dec 31 '19 at 4:48
  • \$\begingroup\$ @Linny The main reason I didn't dump the whole code is because only about 2/3 of it is done/in function form. The whole bottom of main.py is just a test of each function, and the arg parsing is still at the top without being in a function. \$\endgroup\$ – Theo Dec 31 '19 at 4:51
  • \$\begingroup\$ We have a character limit of just over 65k for questions. If it fits (code + current description), feel free to post it. But I'm not sure you want a review. I think you're really asking a design question here, which would fit better elsewhere. But it doesn't feel right to redirect you again (don't mind the people from Stack Overflow, half the time they don't have a clue what we do and don't do), so we can review the code with your concerns in mind. Hint: if the code is long enough, the best answer is never option 1. \$\endgroup\$ – Mast Dec 31 '19 at 9:00
2
\$\begingroup\$

Putting all of your code into a single file is bad. As a very VERY loose rule of thumb I try to avoid having any source file be more than a thousand lines of code, but the real rule to follow is that code should be broken up into modules that have coherent and comprehensible purposes, and those modules should live in their own files.

The origin of rules of thumb like "no file longer than a thousand lines" is that if a file is really long, it's no longer comprehensible by a normal human brain, and so you need to think about how to break your logic down into smaller and more mentally-digestible pieces. A function (or group of interrelated functions) that is long but is self-contained and doesn't interact with anything else would make a lot of sense to have in its own file/module.

I'd probably do my argument parsing right in the main function unless the arg parsing was so complex that it felt like it needed to be its own module.

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ One more question - If the main.py file only needs to call the create_page() function from drawimage.py, should I only from drawimage import create_page() since that function calls the other functions in its file by itself, or do i still import everything? \$\endgroup\$ – Theo Dec 31 '19 at 18:00
  • \$\begingroup\$ Only import what you need (but don't include the () in the import statement, that's not how that works). In addition, if the other functions in that module are "private", you should prefix their names with underscores (e.g. _private_function()) to indicate that they're not meant to be imported or used elsewhere. \$\endgroup\$ – Sam Stafford Dec 31 '19 at 20:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.