1

I am new to OOP and Python in general and having the following problem: Suppose I have a file containing the data line by line that I want to use to create class instances. What is the most pythonic way of processing the file, initializing instances and storing them? I have 3 alternative methods: CASE-1: class method that processes the whole file line by line, creating instances and storing them in a list CASE-2: function outside of the class doing the same as CASE-1 CASE-3: function outside of the class processing each line individually and a for loop in main e.g:

    class TestClass:
    all_instances_1 = []

    def __init__(self, var1, var2):
        self.var1 = var1
        self.var2 = var2

#CASE-1
    @classmethod
    def from_file(cls, input_file):
        my_file = open(input_file, "r")
        for line in my_file:
            var1, var2 = line.split(',')
            new_instance = TestClass(var1, var2])
            cls.all_instances_1.append(new_instance)
        my_file.close()

#CASE-2
def outside_class_init(input_file):
    all_instances_2 = []
    my_file = open(input_file, "r")
    for line in my_file:
        var1, var2 = line.split(',')
        new_instance = TestClass(var1, var2])
        all_instances_2.append(new_instance)
    my_file.close()
    return all_instances_2

#CASE-3
def one_by_one(my_str):
    var1, var2 = line.split(',')
    new_instance = TestClass(var1, var2])
    return new_instance

def main():
    filename = "$FILE"
    TestClass.from_file(filename)
    instances_list2 = outside_class_init(thefile)

    all_instances_3 = []
    my_file = open(thefile, "r")
    for line in my_file:
        all_instances_3.append(one_by_one(line))
    my_file.close()


if __name__ == '__main__':
    main()

If none of them is truly a good approach how would you handle it? Thank you in advance

2
  • Looks like a job for a Factory en.wikipedia.org/wiki/Factory_method_pattern#Python Commented Jul 21, 2021 at 12:42
  • Thank you for the answer! Could you elaborate a little though? Also I failed to mention it in the description, but this would be for a smaller program with 3 classes (for the instances of the first one I have data in a csv, for another in a json, and the third one will be created using informatics of the first 2 classes that I mentioned). Commented Jul 21, 2021 at 13:15

1 Answer 1

1

TestClass is combining two different abstractions: a representation of a single pair of values, and a collection of those pairs. There should be two separate classes. Here's an example:

class Pair:
    def __init__(self, var1, var2):
        self.var1 = var1
        self.var2 = var2

    @classmethod
    def from_string(cls, s):
        v1, v2 = s.split(",")
        return cls(v1, v2)


class LotsaPairs:
    def __init__(self, pairs):
        self.pairs = pairs

    @classmethod
    def from_file(cls, f):
        return cls([Pair.from_string(line.strip()) for line in f])


def main():
    filename = "$FILE"
    with open(filename) as f:
        all_instances = LotsaPairs.from_file(f)

A few observations:

  1. __init__ in both classes is "dumb"; all it does is initialize attributes with a given argument.

  2. The class methods take care of "extracting" data from a specific source to compute the necessary value for __init__.

  3. LotsaPairs.from_file takes a file-like object, not a file name. Let the caller provide that object, to make testing either. (You could pass an io.StringIO instance instead, for example.)

  4. LotsaPairs is a glorified wrapper around a list. You could dispense with it and replace it with a single function:

    def get_pairs(f):
        return [Pairs.from_string(line.strip()) for line in f]
    
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.