HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Indenting a function to recursively find filenames

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
functionrecursivelyfindfilenamesindenting

Problem

I wrote this function that recursively traverses a given directory resolves
the relative file-names to absolute file-names and yields the resolved file-name if it matches a given pattern. You can specify a callback function as well.

The first issue I have with this function is that it is a bit hard to comprehend, I think this problem can be reduced with proper indentation of the generator expressions.

The second thing I would like help with is, How do i reduce the repeated block of code?

import fnmatch
import os
import sys

def find(root, pattern, *callback):
    if not callback:
        for _, _, files in  ((root, _, (os.path.join(root, filename)
        for filename in files if fnmatch.fnmatch(filename, pattern)))
        for (root, _, files) in os.walk(root)):
            for filename in files:
                yield filename

    callback = callback[0]
    for _, _, files in  ((root, _, (os.path.join(root, filename)
    for filename in files if fnmatch.fnmatch(filename, pattern)))
    for (root, _, files) in os.walk(root)):
        for filename in files:
            yield callback(filename)

def cb(filename):
    print filename

for filename in find('/home/dwilson', '*.py', cb):
    pass

Solution

A good way would be to eliminate duplicate using a default callback that does nothing:

def walker(root, pattern):
    for _, _, files in  ((root, _, (os.path.join(root, filename)
        for filename in files if fnmatch.fnmatch(filename, pattern)))
        for (root, _, files) in os.walk(root)):
            for filename in files:
                yield filename

def find(root, pattern, callback=lambda v:v):
    for filename in walker(root, pattern):
        yield callback(filename)


Afterwards, we simplify the walker to

def walker(root, pattern):
    for (root, _, files) in os.walk(root):
        for filename in files:
            if fnmatch.fnmatch(filename, pattern):
                yield os.path.join(root, filename)


and have a much more readable thing than before.

Code Snippets

def walker(root, pattern):
    for _, _, files in  ((root, _, (os.path.join(root, filename)
        for filename in files if fnmatch.fnmatch(filename, pattern)))
        for (root, _, files) in os.walk(root)):
            for filename in files:
                yield filename

def find(root, pattern, callback=lambda v:v):
    for filename in walker(root, pattern):
        yield callback(filename)
def walker(root, pattern):
    for (root, _, files) in os.walk(root):
        for filename in files:
            if fnmatch.fnmatch(filename, pattern):
                yield os.path.join(root, filename)

Context

StackExchange Code Review Q#80560, answer score: 2

Revisions (0)

No revisions yet.