#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2012
    Posts
    14
    Rep Power
    0

    Loop to Efficiently Populate Class Attributes


    Hello,

    I am starting to get into classes in Python and have the following case:

    I am reading a CSV file with 61 columns (each column with a unique header label). I created a class with 61 attributes (I apologize if I'm using the terms incorrectly). A portion of the class is below:

    Code:
    class partProperties:
        def setPartID(self, number):
            self.partID = number
        def setPartName(self, text):
            self.partName = text

    Only 2 of the 61 functions are shown. I would like to read each row of the CSV and 'automatically' set the attributes for a new instance of this class (each row will be an instance). The list of attributes in the class is in the same order as the columns in the CSV.

    My question: is there a way to set all of the attributes without typing each unique call (i.e. 'setPartID')? Ideally I would like to index each attribute so I can loop through all of them as I read each row of the CSV. Is this possible? How would an experienced programmer approach this?

    Thanks.

    -John
  2. #2
  3. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,841
    Rep Power
    480

    This answer is ridiculous.


    The attributes of the class are data driven. Why are the generic objects better than dictionaries? I can't think of a reason. One could insert a price method that depends on item featues, and that would be a good reason to use a custom class instead of a dictionary. The class is restrictive, the keys need to be valid python identifiers.
    Code:
    import io
    import sys
    import csv
    import pprint
    
    class generic(dict):
        pass
    
    def generic_factory(file_object):
        reader = iter(csv.reader(file_object))
        attributes = next(reader)
        result = []
        try:
            while True:
                row = next(reader)
                kwargs = dict(zip(attributes,row))
                result.append(generic(**kwargs))
        except StopIteration:
            pass
        return result
    
    DATA = '"partID","partName"\n35553,"snare"\n28709,"rim"\n85332,"skin"'
    
    if sys.version[0] == '2':
        DATA = DATA.decode('utf8')
    
    FAKEFILE = io.StringIO(DATA)
    
    FAKEFILE.seek(0)
    
    OBJECTS = generic_factory(FAKEFILE)
    
    FAKEFILE.close()
    
    pprint.pprint([str(O) for O in OBJECTS])
    It occurs to me this is easier:
    Code:
    import io
    import sys
    import csv
    import pprint
    
    DATA = '"partID","partName"\n35553,"snare"\n28709,"rim"\n85332,"skin"'
    
    if sys.version[0] == '2':
        DATA = DATA.decode('utf8')
    
    with io.StringIO(DATA) as FAKEFILE:
        FAKEFILE.seek(0)
        OBJECTS = [O for O in csv.DictReader(FAKEFILE)]
    
    pprint.pprint([str(O) for O in OBJECTS])
    Last edited by b49P23TIvg; February 12th, 2013 at 07:10 PM.
    [code]Code tags[/code] are essential for python code and Makefiles!
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2012
    Posts
    14
    Rep Power
    0
    Thank you very much for the response. I am impressed how concise the code is to read the CSV into a dictionary. I need to spend some time studying your code to understand it.

    The challenge I'm facing is that each CSV file that is read may contain only a subset of the 61 columns in the 'master' header.

    If I decide to go the class route, is there a way of defining new instances on the fly from a dynamic variable name?

    For example, as each row is read, the instances are created and named:

    'part-1'
    'part-2'
    'part-3'

    From what I've seen, it appears I may need to use eval for this?

    -John
  6. #4
  7. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2012
    Posts
    14
    Rep Power
    0
    After experimenting, it seems that the following code accomplishes instantiation from dynamic variable names:

    Code:
    partObjectNames.insert(i, 'line-' + str(i) + '-part')	# Create the name of the object to hold the extracted inputs
    partObjectNames[i] = partProperties(extractedInputs)	# Instantiate the object

IMN logo majestic logo threadwatch logo seochat tools logo