Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Yield & closing file objects properly

I have the following class:

class JsonIterator(object):
    def __init__(self,folder):
        self.root = os.path.join(os.getcwd(), folder)
        self.fis = [fi for fi in os.listdir(folder) if "lyrics" in fi]

    def __iter__(self):
        i = 0
        with open(os.path.join(self.root,self.fis[i])) as f:
            yield json.load(f)
        i += 1

It's not working how I want it to--it seems not to get beyond the first file. I've tried

def __iter__(self):
    i = 0
    f = open(os.path.join(self.root, self.fis[i]))
    js = json.load(f)
    f.close()
    yield js
    i += 1

But either way, len(list(JsonIterator("path/to/myfolder"))) gives me 1, and I know for a fact that there is more than one file in the folder. The alternative, of course, would be something like

def __iter__(self):
    i = 0
    yield json.load(open(os.path.join(self.root, self.fis[i])))
    i += 1

but all those dangling open files suck up so much memory my process gets killed.

So what should I do? I thought about writing some kind of decorator, but I don't really understand how those work, or even if it'd solve my problem.

Thanks!

like image 778
swizzard Avatar asked May 06 '26 19:05

swizzard


1 Answers

You need to loop over the filenames in self.fis:

class JsonIterator(object):
    def __init__(self,folder):
        self.root = os.path.join(os.getcwd(), folder)
        self.fis = [fi for fi in os.listdir(folder) if "lyrics" in fi]

    def __iter__(self):
        for fi in self.fis:
            with open(os.path.join(self.root, fi)) as f:
                obj = json.load(f)
            yield obj
like image 176
unutbu Avatar answered May 08 '26 10:05

unutbu