diff --git a/faker/providers/lorem/__init__.py b/faker/providers/lorem/__init__.py
index 48276aa5..55d25543 100644
--- a/faker/providers/lorem/__init__.py
+++ b/faker/providers/lorem/__init__.py
@@ -26,7 +26,7 @@ class Provider(BaseProvider):
     word_connector = ' '
     sentence_punctuation = '.'
 
-    def words(self, nb=3, ext_word_list=None):
+    def words(self, nb=3, ext_word_list=None, unique=False):
         """
         :returns: An array of random words. for example: ['Lorem', 'ipsum', 'dolor']
 
@@ -34,10 +34,13 @@ class Provider(BaseProvider):
         :param nb: how many words to return
         :param ext_word_list: a list of words you would like to have instead of
             'Lorem ipsum'
+        :param unique: If True, the returned word list will contain unique words
 
         :rtype: list
         """
         word_list = ext_word_list if ext_word_list else self.word_list
+        if unique:
+            return self.random_sample(word_list, length=nb)
         return self.random_choices(word_list, length=nb)
 
     def word(self, ext_word_list=None):

Ensure words() returns a unique list of words without duplicates
When calling `words(10)` there is no guarantee that the returned list of elements is unique.   While I could do `set(words(10))`, this may only return 9 items when I am in need of 10.

If creating a list of words with potential duplicates is a useful feature to some, maybe adding an optional parameter called `unique` to the `words` generator could prove useful.
diff --git a/tests/test_factory.py b/tests/test_factory.py
index 39ed0084..7b28a767 100644
--- a/tests/test_factory.py
+++ b/tests/test_factory.py
@@ -330,6 +330,91 @@ class FactoryTestCase(unittest.TestCase):
         word = fake.word(ext_word_list=my_word_list)
         self.assertIn(word, my_word_list)
 
+    def test_no_words(self):
+        fake = Faker()
+
+        words = fake.words(0)
+        self.assertEqual(words, [])
+
+    def test_some_words(self):
+        fake = Faker()
+
+        num_words = 5
+        words = fake.words(num_words)
+        self.assertTrue(isinstance(words, list))
+        self.assertEqual(len(words), num_words)
+
+        for word in words:
+            self.assertTrue(isinstance(word, string_types))
+            self.assertTrue(re.match(r'^[a-z].*$', word))
+
+    def test_words_ext_word_list(self):
+        fake = Faker()
+
+        my_word_list = [
+            'danish',
+            'cheesecake',
+            'sugar',
+            'Lollipop',
+            'wafer',
+            'Gummies',
+            'Jelly',
+            'pie',
+        ]
+
+        num_words = 5
+        words = fake.words(5, ext_word_list=my_word_list)
+        self.assertTrue(isinstance(words, list))
+        self.assertEqual(len(words), num_words)
+
+        for word in words:
+            self.assertTrue(isinstance(word, string_types))
+            self.assertIn(word, my_word_list)
+
+    def test_words_ext_word_list_unique(self):
+        fake = Faker()
+
+        my_word_list = [
+            'danish',
+            'cheesecake',
+            'sugar',
+            'Lollipop',
+            'wafer',
+            'Gummies',
+            'Jelly',
+            'pie',
+        ]
+
+        num_words = 5
+        words = fake.words(5, ext_word_list=my_word_list)
+        self.assertTrue(isinstance(words, list))
+        self.assertEqual(len(words), num_words)
+
+        checked_words = []
+        for word in words:
+            self.assertTrue(isinstance(word, string_types))
+            self.assertIn(word, my_word_list)
+            # Check that word is unique
+            self.assertTrue(word not in checked_words)
+            checked_words.append(word)
+
+    def test_unique_words(self):
+        fake = Faker()
+
+        num_words = 20
+        words = fake.words(num_words, unique=True)
+        self.assertTrue(isinstance(words, list))
+        self.assertEqual(len(words), num_words)
+
+        checked_words = []
+        for word in words:
+            self.assertTrue(isinstance(word, string_types))
+            # Check that word is lowercase letters. No numbers, symbols, etc
+            self.assertTrue(re.match(r'^[a-z].*$', word))
+            # Check that word list is unique
+            self.assertTrue(word not in checked_words)
+            checked_words.append(word)
+
     def test_random_pystr_characters(self):
         from faker.providers.python import Provider
         provider = Provider(self.generator)

pip install -e .
parse_log_pytest
requirements.txt
pytest
3.9
tests/requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
dnspython==2.7.0
email-validator==1.0.3
exceptiongroup==1.2.2
-e git+https://github.com/joke2k/faker.git@fc546bca9b4f411e8565aeb5ddd9ccee8de59494#egg=Faker
idna==3.10
iniconfig==2.1.0
mock==2.0.0
packaging==24.2
pbr==6.1.1
pluggy==1.5.0
pytest==8.3.5
python-dateutil==2.9.0.post0
six==1.17.0
text-unidecode==1.2
tomli==2.2.1
UkPostcodeParser==1.1.2

name: faker
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - dnspython==2.7.0
      - email-validator==1.0.3
      - exceptiongroup==1.2.2
      - idna==3.10
      - iniconfig==2.1.0
      - mock==2.0.0
      - packaging==24.2
      - pbr==6.1.1
      - pluggy==1.5.0
      - pytest==8.3.5
      - python-dateutil==2.9.0.post0
      - six==1.17.0
      - text-unidecode==1.2
      - tomli==2.2.1
      - ukpostcodeparser==1.1.2
prefix: /opt/conda/envs/faker

tests/test_factory.py::FactoryTestCase::test_unique_words
tests/test_factory.py::FactoryTestCase::test_ipv4_public tests/test_factory.py::FactoryTestCase::test_ipv4_public_class_c tests/test_factory.py::FactoryTestCase::test_words_ext_word_list_unique
tests/test_factory.py::FactoryTestCase::test_add_provider_gives_priority_to_newly_added_provider tests/test_factory.py::FactoryTestCase::test_binary tests/test_factory.py::FactoryTestCase::test_cli_seed tests/test_factory.py::FactoryTestCase::test_cli_seed_with_repeat tests/test_factory.py::FactoryTestCase::test_cli_verbosity tests/test_factory.py::FactoryTestCase::test_command tests/test_factory.py::FactoryTestCase::test_command_custom_provider tests/test_factory.py::FactoryTestCase::test_documentor tests/test_factory.py::FactoryTestCase::test_email tests/test_factory.py::FactoryTestCase::test_ext_word_list tests/test_factory.py::FactoryTestCase::test_format_calls_formatter_on_provider tests/test_factory.py::FactoryTestCase::test_format_transfers_arguments_to_formatter tests/test_factory.py::FactoryTestCase::test_get_formatter_returns_callable tests/test_factory.py::FactoryTestCase::test_get_formatter_returns_correct_formatter tests/test_factory.py::FactoryTestCase::test_get_formatter_throws_exception_on_incorrect_formatter tests/test_factory.py::FactoryTestCase::test_instance_seed_chain tests/test_factory.py::FactoryTestCase::test_invalid_locale tests/test_factory.py::FactoryTestCase::test_ipv4 tests/test_factory.py::FactoryTestCase::test_ipv4_network_class tests/test_factory.py::FactoryTestCase::test_ipv4_private tests/test_factory.py::FactoryTestCase::test_ipv4_private_class_a tests/test_factory.py::FactoryTestCase::test_ipv4_private_class_b tests/test_factory.py::FactoryTestCase::test_ipv4_private_class_c tests/test_factory.py::FactoryTestCase::test_ipv4_public_class_a tests/test_factory.py::FactoryTestCase::test_ipv4_public_class_b tests/test_factory.py::FactoryTestCase::test_ipv6 tests/test_factory.py::FactoryTestCase::test_language_code tests/test_factory.py::FactoryTestCase::test_locale tests/test_factory.py::FactoryTestCase::test_magic_call_calls_format tests/test_factory.py::FactoryTestCase::test_magic_call_calls_format_with_arguments tests/test_factory.py::FactoryTestCase::test_nl_BE_ssn_valid tests/test_factory.py::FactoryTestCase::test_no_words tests/test_factory.py::FactoryTestCase::test_no_words_paragraph tests/test_factory.py::FactoryTestCase::test_no_words_sentence tests/test_factory.py::FactoryTestCase::test_parse_returns_same_string_when_it_contains_no_curly_braces tests/test_factory.py::FactoryTestCase::test_parse_returns_string_with_tokens_replaced_by_formatters tests/test_factory.py::FactoryTestCase::test_password tests/test_factory.py::FactoryTestCase::test_prefix_suffix_always_string tests/test_factory.py::FactoryTestCase::test_random_element tests/test_factory.py::FactoryTestCase::test_random_number tests/test_factory.py::FactoryTestCase::test_random_pyfloat tests/test_factory.py::FactoryTestCase::test_random_pystr_characters tests/test_factory.py::FactoryTestCase::test_random_sample_unique tests/test_factory.py::FactoryTestCase::test_slugify tests/test_factory.py::FactoryTestCase::test_some_words tests/test_factory.py::FactoryTestCase::test_us_ssn_valid tests/test_factory.py::FactoryTestCase::test_words_ext_word_list tests/test_factory.py::FactoryTestCase::test_words_valueerror
faker/providers/lorem/__init__.py
faker/providers/lorem/__init__.py