diff --git a/Doc/library/fnmatch.rst b/Doc/library/fnmatch.rst
index c03a9d3..be697b0 100644
--- a/Doc/library/fnmatch.rst
+++ b/Doc/library/fnmatch.rst
@@ -71,6 +71,12 @@ patterns.
Return the subset of the list of *names* that match *pattern*. It is the same as
``[n for n in names if fnmatch(n, pattern)]``, but implemented more efficiently.
+.. function:: filter_false(names, pattern)
+
+ Return the subset of the list of *names* that don't match *pattern*. It is the
+ same as ``[n for n in names if not fnmatch(n, pattern)]``, but implemented more
+ efficiently.
+
.. function:: translate(pattern)
diff --git a/Lib/fnmatch.py b/Lib/fnmatch.py
index fd3b514..3a4b7ed 100644
--- a/Lib/fnmatch.py
+++ b/Lib/fnmatch.py
@@ -14,7 +14,7 @@ import posixpath
import re
import functools
-__all__ = ["filter", "fnmatch", "fnmatchcase", "translate"]
+__all__ = ["filter", "filter_false", "fnmatch", "fnmatchcase", "translate"]
def fnmatch(name, pat):
"""Test whether FILENAME matches PATTERN.
@@ -47,19 +47,23 @@ def _compile_pattern(pat):
def filter(names, pat):
"""Return the subset of the list NAMES that match PAT."""
- result = []
pat = os.path.normcase(pat)
match = _compile_pattern(pat)
+ return _filtered(names, match)
+
+def filter_false(names, pat):
+ """Return the subset of the list NAMES that don't match PAT."""
+ pat = os.path.normcase(pat)
+ match = _compile_pattern(pat)
+ return _filtered(names, lambda name: match(name) is None)
+
+def _filtered(names, matcher):
if os.path is posixpath:
# normcase on posix is NOP. Optimize it away from the loop.
- for name in names:
- if match(name):
- result.append(name)
+ return [name for name in names if matcher(name)]
else:
- for name in names:
- if match(os.path.normcase(name)):
- result.append(name)
- return result
+ normcase = os.path.normcase
+ return [name for name in names if matcher(normcase(name))]
def fnmatchcase(name, pat):
"""Test whether FILENAME matches PATTERN, including case.
diff --git a/Lib/test/test_fnmatch.py b/Lib/test/test_fnmatch.py
index fb74246..2e15ad3 100644
--- a/Lib/test/test_fnmatch.py
+++ b/Lib/test/test_fnmatch.py
@@ -2,7 +2,7 @@
import unittest
-from fnmatch import fnmatch, fnmatchcase, translate, filter
+from fnmatch import fnmatch, fnmatchcase, translate, filter, filter_false
class FnmatchTestCase(unittest.TestCase):
@@ -78,5 +78,11 @@ class FilterTestCase(unittest.TestCase):
self.assertEqual(filter(['a', 'b'], 'a'), ['a'])
+class FilterFalseTestCase(unittest.TestCase):
+
+ def test_filter_false(self):
+ self.assertEqual(filter_false(['a', 'b'], 'a'), ['b'])
+
+
if __name__ == "__main__":
unittest.main()