[Tutor] Only appending one object to list, when I am expecting more than 1

Cameron Simpson cs at cskk.id.au
Tue Feb 26 04:59:35 EST 2019


Thank you for a well formed problem description.

However, as Steven has remarked the code you've included doesn't run.  
Can you follow up/reply with your actual working script, and also 
include some of the output you get.

That said, I've a few small remarks about the code you have posted:

On 26Feb2019 09:09, AdamC <kabads at gmail.com> wrote:
>I'm creating lots of objects from json in a file. Part of reading the json
>back means that it iterates over the file and loads a json object and then
>creates the object from the dictionary.
>
>This is my  file:
>
>{"name": "Dwarf Fortress", "platform": "steam", "dateAdded":
>"2019:02:25:16:56:1551113768", "tpe": "2019:02:21:13:49:1550756942"}
>{"name": "Jaws", "platform": "Netflix", "dateAdded":
>"2019:02:25:16:56:1551113768", "tpe": "2019:02:21:13:49:1550756960"}
>{"name": "Wargames", "platform": "CLI", "dateAdded":
>"2019:02:25:16:59:1551113984", "tpe": "Game"}

BTW, I notice that only one of these rows has the "tpe" field set to 
"Game" or "Film", specificly the last one. So based on your code below, 
only one of these rows gets appended to the media array. Remarks below 
on writing code which is less prone to hiding this kind of problem.

>and these are the functions that help load that file:
>
>media = []
>
>def loadFile():
>    filename = input('Filename? ')
>    f = open(filename, 'r')
>    createObjects(f)

This f=open code would normally be written like this:

    with open(filename, 'r') as f:
        createObjects(f)

That construction ensures that the file gets closed after running 
"createObjects()". As it is in your code the file is not explicitly 
closed; the CPython interpreter will, as it happens, close the file 
pretty promptly when "f" goes out of scope, but the language definition 
doesn't require such immediacy.

>def createObjects(f):
>    '''Takes a file object and iterates through entries, passing them to
>create
>    object, depending on what object it is.'''
>    for line in f:
>        count = count + 1
>        data = json.loads(line)
>        print(type(data['tpe']))
>        name = data['name']
>        platform = data['platform']
>        dateAdded = data['dateAdded']
>        tpe = data['tpe']
>        if data['tpe'] == 'Game':
>            a = createGame(name, platform, dateAdded,tpe)
>            game = {a: tpe}
>            media.append(game)
>        if data['tpe'] == 'Film':
>            a = createFilm(name, platform, dateAdded,tpe)
>            film = {a: tpe}
>            media.append(film)

These if statements don't cover the case when "tpe" isn't "Game" or 
"Film", and (in other circumstances) could conceivably add two objects.  
If you construct it like this instead:

        if data['tpe'] == 'Game':
            a = createGame(name, platform, dateAdded,tpe)
            game = {a: tpe}
            media.append(game)
        elif data['tpe'] == 'Film':
            a = createFilm(name, platform, dateAdded,tpe)
            film = {a: tpe}
            media.append(film)
        else:
            print("Unhandled tpe value:", repr(tpe))

then (a) only 1 branch can ever apply and (b) reports any unexpected 
values which would otherwise _silently_ get ignored. By always having a 
final "else" in an if/elif/..../else chain you can catch/observe these 
unhandled situations.

>def createGame(name, platform, dateAdded, tpe):
>    return Game(name, platform, dateAdded)
>
>def createFilm(name, platform, dateAdded, tpe):
>    return Film(name, platform, dateAdded)

Unless there's more stuff happening in these functions which you've 
stripped out for clarity you could just call the object constructors 
directly from the if statements:

    if data['tpe'] == 'Game':
        a = Game(name, platform, dateAdded)
        game = {a: tpe}
        media.append(game)

>Why would I only get one object in media, even though all three are 
>created?

As you may gather, all three input lines are processed, but only one 
gets turned into an object to add to media. Change the if/if into an 
if/elif/else and see if things become more obvious.

Cheers,
Cameron Simpson <cs at cskk.id.au>


More information about the Tutor mailing list