Challenge:
change the code so that only .py and .txt files of a given directory are listed.

''' filename_list_given_dir1.py
use module glob to list all the filenames of .jpg files
or any extension(s) you specify in a given directory
'''

import glob
import os

# all files (split off file names) in a given directory
directory = "C:/Temp/*.jpg"
# this would give you all files
#directory = "C:/Temp/*.*"
for path in glob.glob(directory):
    #print(path)  # test
    # separate path from filename
    dirname, filename = os.path.split(path)
    print(filename)

Dani AI

Generated

A few practical points and a compact, modern pattern to complement the thread: for clarity and robustness prefer the pathlib API (Python 3.4+) or os.scandir (Python 3.5+) rather than changing the current directory or building big intermediate lists. Pathlib gives Path objects (no manual split/join), makes the suffix check explicit, and lets you iterate lazily. This builds on ideas from , , and while avoiding side effects like chdir and the pitfalls of naive regex matching noted by .

from pathlib import Path

p = Path(r'C:\Temp')            # or Path('/path/to/dir')
matches = [f.name for f in p.iterdir()
           if f.is_file() and f.suffix.lower() in {'.py', '.txt'}]

Notes and troubleshooting tips:

  • Using f.suffix.lower() handles mixed-case extensions (e.g. .Py) consistently across platforms. On Windows most filesystems are case-insensitive, but normalizing to lower() is portable.
  • For recursion use rglob() or iterate and check suffix; for very large folders prefer os.scandir() or pathlib (which uses scandir internally on modern Pythons) to reduce overhead.
  • Avoid os.chdir() inside helpers — it hides bugs and breaks callers (see / exchange). Return clear errors or raise exceptions instead.
  • If combining multiple patterns (as suggested), dedupe results with a set to avoid duplicates from overlapping patterns or symlinks.
  • Be careful with regex-based filters: filenames can contain unusual characters (including newlines), so suffix-based checks or Path.suffix are more robust for the simple “which extension” problem the OP asked about.

This keeps the result as filenames only (no manual split), is cross-platform friendly, and scales better than building full lists from many glob calls.

Recommended Answers

All 14 Replies

Member Avatar for Member #46692

Would you change *.jpg to *.py

You can change *.jpg to *.py, but that won't show you the .txt files.

One idea, the result of glob.glob(path) is a list, so you could add the two lists
list_py_txt = glob.glob("c:/temp/*.py") + glob.glob("c:/temp/*.txt")

I would get rid of the glob.glob totally as we deal only with ends.

filenames = [path for path in os.listdir(directory) if path.endswith(('.py', '.txt'))]

Hm, os.listdir() returns names, one probably needs

filenames = [os.path.join(directory, name) for name in os.listdir(directory) if name.endswith(('.py', '.txt'))]

OP wanted only names and used os.path.split, which os.listdir makes unnecessary.

The nice thing about glob.glob() is that handles mixed case extensions like .Py or .TxT or .Txt that sometimes appear.

Would need to use the .lower() in addition to endswith to deal with that. And the file name should not really be called path.

filenames = [file_name for file_name in os.listdir(directory) if file_name.lower().endswith(('.py', '.txt'))]

Regex's anyone?

from re import search, I
from os import listdir

print [f for f in listdir('.') if search("\.py$|\.txt$", f, I) != None]

Regex's anyone?

I would use

r".*(?:\.py|\.txt)\Z(?ims)"

because glob uses fnmatch, which translates shell patterns into python regex, and this is how '.*' is translated:

>>> from fnmatch import translate
>>> translate('*.py')
'.*\\.py\\Z(?ms)'

I think it makes a difference if file names contain newline characters. The following works in my linux system, creating a file name containing newlines

>>> with open("foo\nbar.txt\n", "w") as ofh:
...  ofh.write('foobar')
... 
>>> 

your regex will list this file which does not end with .txt.

commented: good point! +7

I give it a try for fun.

#multi_glob.py
from glob import glob
import os

def multi_glob(path=None, *args):
    '''glob that can handle multiple file extensions option.
    #--- Usage ---#
    from multi_glob import multi_glob
    multi_glob(folder_path, '*.py', '*.txt')
    '''
    try:
        os.chdir(path)
    except OSError:
        os.chdir(os.getcwd())
        print 'Wrong path using script(.py) folder path'
    f_lst = []
    for files in args:
        f_lst.extend(glob(files))
    return f_lst

Test:

>>> from multi_glob import multi_glob
>>> print multi_glob(r'C:\temp999', '*.py', '*.txt')
Wrong path using script(.py) folder path
['02252014-162200.709116.txt', 'saladsfilecost.txt']

>>> print multi_glob(r'C:\temp', '*.py', '*.txt')
['micc.py', 'module9.py', 'tid_delta_csv.py', 'pass.txt', 'VRayLog.txt']

>>> help(multi_glob)
Help on function multi_glob in module __main__:

multi_glob(path=None, *args)
    glob that can handle multiple file extensions option.
    #--- Usage ---#
    from multi_glob import multi_glob
    multi_glob(folder_path, '*.py', '*.txt')

os.chdir(os.getcwd())

This is a no-op :)

This is a no-op :)

Yes i can agree with that :)

#multi_glob.py
from glob import glob
import os

def multi_glob(path=None, *args):
    '''glob that can handle multiple file extensions option.
    #--- Usage ---#
    from multi_glob import multi_glob
    multi_glob(folder_path, '*.py', '*.txt')
    '''
    try:
        os.chdir(path)
    except OSError:
        return 'Wrong folder path,try again'
    f_lst = []
    for files in args:
        f_lst.extend(glob(files))
    return f_lst

Test:

>>> from multi_glob import multi_glob
>>> print multi_glob(r'C:\temp', '*.py', '*.txt')
['micc.py', 'module9.py', 'tid_delta_csv.py', 'pass.txt', 'VRayLog.txt']
>>> print multi_glob(r'C:\temp999', '*.py', '*.txt')
Wrong folder path,try again

Here a version of iglob,that can take multiple file extensions.

#iter_glob
from glob import iglob
from itertools import chain
import os, sys

def iter_glob(path=None, *args):
    '''A iglob version that return an iterator fully lazy evaluated
     and can handle multiple file extensions.
    #--- Usage ---#
    from iter_glob import iter_glob
    for filename in multi_glob(folder_path, '*.py', '*.txt'):
        print filename
    '''
    try:
        os.chdir(path)
    except Exception as error:
        print 'Wrong folder path {},try again'\
        .format(str(error).split(':',1)[-1].strip())
        sys.exit()
    return chain.from_iterable(iglob(pattern) for pattern in args)

Test:

>>> from iter_glob import  iter_glob
>>> for filename in iter_glob(r'C:\temp', '*.py', '*.txt'):
...     print filename
...     
micc.py
module9.py
tid_delta_csv.py
pass.txt
VRayLog.txt

>>> for filename in iter_glob(r'C:\temp999', '*.py', '*.txt'):
...     print filename
...     
Wrong folder path 'C:\\temp999',try again
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.