Read a txt file and split into 2 csvs based on regex So I have been told that my code is not good and needs refactoring. I'm struggling to see what I need to do. How do I specify the success and failure conditions for lambda? Also don't get what the method process_lines should contain. Any help is greatly appreciated!
These are the comments I was given:

Let's create a function (process _lines) that accepts 2 lambda functions (success, failure). The success will accept the function pointer that will write to good csv file, while failure to the bad csv file.
Something like:
def process_lines(success, failure):
...
def write_to_csv(csv_file):
...
process_lines(lambda: write_to_csv(good_csv), lambda: write_to_csv(bad_csv))


Currently this is my code:
import re
import csv

pattern = re.compile(&quot;([0-9]+) +([0-9\.-]+) +([0-9\.\-+Ee]+) +([0-9\.\-+Ee]+) +([0-9\.\-+Ee]+) +([0-9\.\-+Ee]+) +([0-9\.\-+Ee]+) +([0-9\.\-+Ee]+) +([0-9\.\-+Ee]+) +([0-9\.\-+Ee]+) +([0-9\.\-+Ee]+) +([0-9\.\-+Ee]+) +([0-9\.\-+Ee]+) +([0-9\.\-+Ee]+) +([0-9\.\-+Ee]+) +([0-9\.\-+Ee]+) +([0-9\.\-+Ee]+) +([0-9\.\-+Ee]+) +([0-9\.\-+Ee]+) +([0-9\.\-+Ee]+) +([0-9\.\-+Ee]+) +([0-9\.\-+Ee]+) +([0-9\.\-+Ee]+)&quot;)

good_csv = []
bad_csv = []
fname = &quot;track_param_hist.txt&quot;
good_csv_fname = &quot;good_hist_csv.csv&quot;
bad_csv_fname = &quot;bad_hist_csv.csv&quot;


class ConvertTxtToCsvs:
  def process(self):
    print(&quot;Script for splitting text file into two separate csvs...&quot;)
    # read in the text file and store the lines as a list
    with open(fname) as f:
      lines = f.readlines()

    # split the lines into good and bad
    for line in lines:
      good_csv.append(line) if pattern.match(line) else bad_csv.append(line)

    # create the csv for bad data
    with open(bad_csv_fname, 'w') as myfile:
      wr = csv.writer(myfile)
      for line in bad_csv:
        row = (' '.join(line.split())).split(' ')
        wr.writerow(row)
    print(&quot;Csv for the bad data has been created successfully&quot;)

    # create the csv for good data
    with open(good_csv_fname, 'w') as myfile:
      wr = csv.writer(myfile)
      for line in good_csv:
        row = (' '.join(line.split())).split(' ')
        wr.writerow(row)
    print(&quot;Csv for the good data has been created successfully&quot;)

# This can also be run as regular python script
if __name__ == &quot;__main__&quot;:
  ConvertTxtToCsvs().process()
I really don't know why someone's recommending lambdas to you like that but it's not at all what I'd do. I do agree there's some refactoring that could be done here though.

Refactoring

Why is ConvertTxtToCsvs a class? It contains only one function, process, and no attributes. There's no need for it to be a class. Instead, have it function based, and you should split it up a bit. Notice how writing to the good and bad csvs are mirrors of each other? You should have one write_csv function. Since all the code is the same except the filename and the data, it's very easy to turn into a function:

def write_csv(filename, data):
    with open(filename, 'w') as myfile:
        wr = csv.writer(myfile)
        for line in data:
            row = (' '.join(line.split())).split(' ')
            wr.writerow(row)


And then it can be called for both like this:

write_csv(good_csv_fname, good_data)
print("Csv for the bad data has been created successfully")
write_csv(bad_csv_fname, bad_data)
print("Csv for the good data has been created successfully")


Which is much neater. Also notice I changed from using a 2 space indent to 4 spaces. That's suggested by the Python style guide and is much more readable. This is especially important since whitespace affects program flow in Python.

Also, you read all the lines of the file up front just to iterate over them anyway. It'd be easier and less resource hogging to just read it line by line. Python makes it very easy, as you can directly iterate over a file-like object.

with open(fname) as f:
    for line in f:
        good_csv.append(line) if pattern.match(line) else bad_csv.append(line)


And lastly, you create your two lists before the function is called. This is bad, because you couldn't call the function more than once without accidentally including all the old data. Instead create the two lists inside the function so with each function call you create new empty lists.

Style Notes

I linked the style guide just above and it's a good read, but there's some other stuff I'd like to specifically point out. Some of your namìng isn't helpful. good and bad are often poor descriptions. Why are they good? Does good mean valid data, matching data, useful data? Instead, consider a name more relevant to what that means. matched and unmatched perhaps? Similarly, I'd avoid the use of csv. A csv is a filetype, your lists are not csvs (yet), so you don't need to include that name. 

And don't shorten filename to fname. That shortened three characters isn't worth the reduced clarity here. And instead of just filename it'd be better to use source or source_filename. 

source_filename = "track_param_hist.txt"
matched_data_file = "good_hist_csv.csv"
unmatched_data_file = "bad_hist_csv.csv"
pattern = re.compile("([0-9]+) +([0-9\.-]+)" + "+([0-9\.\-+Ee]+)" * 21)
matched = []
unmatched = []


You have a lot of comments that you don't really need. Comments should explain complex code or intent that's confusing to follow. There's no need comment about using with open and readlines. These are simple to follow functions, Python is highly readable that way. This could be a good line to comment:

            row = (' '.join(line.split())).split(' ')


It took me a moment to realise that it's splitting and rejoining the sentence to ensure that there's only a one space gap instead of any multiple spaces. You should write a comment to clarify this as it's a slightly confusing solution.

Using a ternary in your for loop works fine, but is a little hard to read. Ternaries are really best used when they can remove duplicate code and shorten things. Your case is less lines, but just as many words. This might be a better use of a ternary:

good_csv.append(line if pattern.match(line) else "")


I'd personally think it's better to write the loop this way:

for line in lines:
    if pattern.match(line):
        matched.append(line) 
    else:
        unmatched.append(line)


This is how I'd rewrite your whole script in the end:

import re
import csv


source_filename = "track_param_hist.txt"
matched_data_file = "good_hist_csv.csv"
unmatched_data_file = "bad_hist_csv.csv"
pattern = re.compile("([0-9]+) +([0-9\.-]+)" + "+([0-9\.\-+Ee]+)" * 21)


def write_csv(filename, data):
    with open(filename, 'w') as myfile:
        wr = csv.writer(myfile)
        for line in data:
            # Make sure all whitespace is reduced to one space character
            row = (' '.join(line.split())).split(' ')
            wr.writerow(row)            


def process(source):
    print("Script for splitting text file into two separate csvs...")

    matched = []
    unmatched = []

    with open(source) as f:
        for line in f:
            if pattern.match(line):
                matched.append(line)
            else:
                unmatched.append(line)

    write_csv(matched_data_file, matched)
    print("Csv for the good data has been created successfully")
    write_csv(unmatched_data_file, unmatched)
    print("Csv for the bad data has been created successfully")


if __name__ == "__main__":
    process(source_filename)