diff --git a/src/packageurl/__init__.py b/src/packageurl/__init__.py
index 71225e9..ae6e148 100644
--- a/src/packageurl/__init__.py
+++ b/src/packageurl/__init__.py
@@ -282,6 +282,9 @@ class PackageURL(namedtuple('PackageURL', _components)):
     def __str__(self, *args, **kwargs):
         return self.to_string()
 
+    def __hash__(self):
+        return hash(self.to_string())
+
     def to_dict(self, encode=False):
         """
         Return an ordered dict of purl components as {key: value}. If `encode`

PackageURL type is not hashable
Storing `PackageURL` instances in a set can be useful. Currently attempting this fails with the following error:

```
Python 3.8.2 (default, Feb 26 2020, 22:21:03) 
[GCC 9.2.1 20200130] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from packageurl import PackageURL
>>> {PackageURL(name='test', type='pypi')}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'collections.OrderedDict'
```
diff --git a/tests/test_packageurl.py b/tests/test_packageurl.py
index 912b380..6081912 100644
--- a/tests/test_packageurl.py
+++ b/tests/test_packageurl.py
@@ -286,3 +286,9 @@ class NormalizePurlTest(unittest.TestCase):
             ('subpath', u'this/is/a/path')
         ])
         assert expected == purl.to_dict(encode=True)
+
+
+def test_purl_is_hashable():
+    s = {PackageURL(name='hashable', type='pypi')}
+    assert len(s) == 1
+

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest numpy>=1.16.0 pandas>=1.0.0
apt-get update apt-get install -y gcc
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
exceptiongroup==1.2.2
iniconfig==2.1.0
numpy==2.0.2
-e git+https://github.com/package-url/packageurl-python.git@a762fbd361a253e3c12f7fff61c305b6a69d0ed8#egg=packageurl_python
packaging==24.2
pandas==2.2.3
pluggy==1.5.0
pytest==8.3.5
python-dateutil==2.9.0.post0
pytz==2025.2
six==1.17.0
tomli==2.2.1
tzdata==2025.2

name: packageurl-python
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
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - exceptiongroup==1.2.2
      - iniconfig==2.1.0
      - numpy==2.0.2
      - packaging==24.2
      - pandas==2.2.3
      - pluggy==1.5.0
      - pytest==8.3.5
      - python-dateutil==2.9.0.post0
      - pytz==2025.2
      - six==1.17.0
      - tomli==2.2.1
      - tzdata==2025.2
prefix: /opt/conda/envs/packageurl-python

tests/test_packageurl.py::test_purl_is_hashable
tests/test_packageurl.py::test_packageurl.python_safe_name tests/test_packageurl.py::PurlTest::test_purl_pkg_basic_valid_maven_purl_without_version tests/test_packageurl.py::PurlTest::test_purl_pkg_bitbucket_namespace_and_name_should_be_lowercased tests/test_packageurl.py::PurlTest::test_purl_pkg_debian_can_use_qualifiers tests/test_packageurl.py::PurlTest::test_purl_pkg_docker_uses_qualifiers_and_hash_image_id_as_versions tests/test_packageurl.py::PurlTest::test_purl_pkg_double_slash_after_scheme_is_not_significant tests/test_packageurl.py::PurlTest::test_purl_pkg_github_namespace_and_name_should_be_lowercased tests/test_packageurl.py::PurlTest::test_purl_pkg_is_invalid_a_name_is_required tests/test_packageurl.py::PurlTest::test_purl_pkg_is_invalid_a_scheme_is_always_required tests/test_packageurl.py::PurlTest::test_purl_pkg_is_invalid_a_type_is_always_required tests/test_packageurl.py::PurlTest::test_purl_pkg_is_invalid_checks_for_invalid_qualifier_keys tests/test_packageurl.py::PurlTest::test_purl_pkg_java_gem_can_use_a_qualifier tests/test_packageurl.py::PurlTest::test_purl_pkg_maven_can_come_with_a_type_qualifier tests/test_packageurl.py::PurlTest::test_purl_pkg_maven_often_uses_qualifiers tests/test_packageurl.py::PurlTest::test_purl_pkg_maven_pom_reference tests/test_packageurl.py::PurlTest::test_purl_pkg_npm_can_be_scoped tests/test_packageurl.py::PurlTest::test_purl_pkg_nuget_names_are_case_sensitive tests/test_packageurl.py::PurlTest::test_purl_pkg_pypi_names_have_special_rules_and_not_case_sensitive tests/test_packageurl.py::PurlTest::test_purl_pkg_rpm_often_use_qualifiers tests/test_packageurl.py::PurlTest::test_purl_pkg_slash_after_scheme_is_not_significant tests/test_packageurl.py::PurlTest::test_purl_pkg_slash_after_type_is_not_significant tests/test_packageurl.py::PurlTest::test_purl_pkg_valid_go_purl_with_version_and_subpath tests/test_packageurl.py::PurlTest::test_purl_pkg_valid_go_purl_without_version_and_with_subpath tests/test_packageurl.py::PurlTest::test_purl_pkg_valid_maven_purl tests/test_packageurl.py::PurlTest::test_purl_pkg_valid_maven_purl_containing_a_space_in_the_version_and_qualifier tests/test_packageurl.py::PurlTest::test_purl_pkg_valid_maven_purl_with_case_sensitive_namespace_and_name tests/test_packageurl.py::NormalizePurlTest::test_create_PackageURL_from_qualifiers_dict tests/test_packageurl.py::NormalizePurlTest::test_create_PackageURL_from_qualifiers_string tests/test_packageurl.py::NormalizePurlTest::test_normalize_decode_can_take_unicode_with_non_ascii_with_slash tests/test_packageurl.py::NormalizePurlTest::test_normalize_encode_always_reencodes tests/test_packageurl.py::NormalizePurlTest::test_normalize_encode_can_take_unicode_with_non_ascii_with_slash tests/test_packageurl.py::NormalizePurlTest::test_normalize_qualifiers_as_dict tests/test_packageurl.py::NormalizePurlTest::test_normalize_qualifiers_as_string tests/test_packageurl.py::NormalizePurlTest::test_qualifiers_must_be_key_value_pairs tests/test_packageurl.py::NormalizePurlTest::test_to_dict_optionally_returns_qualifiers_as_string
src/packageurl/__init__.py
src/packageurl/__init__.py