Repository: PlasmaPy/PlasmaPy
Pull request #284 (2018-02-28 20:25:00)

Update and refactor Particle class
This PR continues to implement the changes from our first code review session on the Particle class, with many helpful suggestions from @lemmatum and @StanczakDominik (see also #281).  The changes I made were to:
  - Create `Particle.electron_number` attribute
  - Remove `Particle.reduced_mass` in favor of `reduced_mass` function that was recently added to atomic.py (this changes the API)
 - Instead of defining lists of keys to be used, just get them directly from the `dict` objects
 - Move proton attributes to `special_particles.py`
 - Move `_PeriodicTable` `namedtuple` to `elements.py`
 - Update `neutron_number` attribute so that it returns `1` for a neutron
 - Remove defining an alpha particle as a boson since we should do that for all nuclides/ions instead of doing it for just one


Patch:
diff --git a/plasmapy/atomic/atomic.py b/plasmapy/atomic/atomic.py
index 4ab52c51..5d85bea5 100644
--- a/plasmapy/atomic/atomic.py
+++ b/plasmapy/atomic/atomic.py
@@ -53,7 +53,7 @@ def atomic_number(element: Particle) -> str:
         If the argument does not correspond to a valid particle.
 
     `TypeError`
-        If the argument is not a string.
+        If the argument is not a `str`.
 
     See Also
     --------
@@ -100,7 +100,7 @@ def mass_number(isotope: Particle) -> int:
         If the argument does not correspond to a valid isotope.
 
     `TypeError`
-        The argument is not a string.
+        The argument is not a `str`.
 
 
     See Also
@@ -150,7 +150,7 @@ def standard_atomic_weight(element: Particle) -> u.Quantity:
         If the argument does not correspond to a valid particle.
 
     `TypeError`
-        If the argument is not a string or integer.
+        If the argument is not a `str` or `int`.
 
     See Also
     --------
@@ -178,28 +178,21 @@ def standard_atomic_weight(element: Particle) -> u.Quantity:
 
     Examples
     --------
-    >>> from astropy import units as u
     >>> standard_atomic_weight("H")
-    <Quantity 1.008 u>
-    >>> # the following result accounts for small amount of deuterium
-    >>> standard_atomic_weight("H").to(u.kg)
     <Quantity 1.67382335e-27 kg>
     >>> isotope_mass("H-1")
-    <Quantity 1.00782503 u>
-    >>> standard_atomic_weight(82)
-    <Quantity 207.2 u>
+    <Quantity 1.67353281e-27 kg>
     >>> standard_atomic_weight("lead")
-    <Quantity 207.2 u>
+    <Quantity 3.44063689e-25 kg>
 
     """
     return element.standard_atomic_weight
 
 
 @particle_input(exclude='ion')
-def isotope_mass(isotope: Particle,
-                 mass_numb: int = None) -> u.Quantity:
+def isotope_mass(isotope: Particle, mass_numb: int = None) -> u.Quantity:
     """
-    Return the mass of an isotope.
+    Return the mass of an isotope in kg.
 
     Parameters
     ----------
@@ -225,11 +218,12 @@ def isotope_mass(isotope: Particle,
         If the argument does not correspond to a valid particle.
 
     `~plasmapy.utils.AtomicError`
-        If the charge of the particle is given, in which case ion_mass
-        should be used instead.
+        If the charge of the particle is given, in which case
+        `~plasmapy.atomic.ion_mass` should be used instead.
 
     `TypeError`
-        If `isotope` is not a string, integer, or particle.
+        If `isotope` is not a `str`, `int`, or
+        `~plasmapy.atomic.Particle`.
 
     See Also
     --------
@@ -246,17 +240,16 @@ def isotope_mass(isotope: Particle,
     Examples
     --------
     >>> isotope_mass("H-1")
-    <Quantity 1.00782503 u>
+    <Quantity 1.67353281e-27 kg>
     >>> isotope_mass("He", mass_numb=4)
-    <Quantity 4.00260325 u>
+    <Quantity 6.64647897e-27 kg>
 
     """
     return isotope.mass
 
 
 @particle_input
-def ion_mass(particle: Particle, *, Z: int = None,
-             mass_numb: int = None) -> u.Quantity:
+def ion_mass(particle: Particle, *, Z: int = None, mass_numb: int = None) -> u.Quantity:
     """
     Return the mass of an ion by finding the standard atomic
     weight of an element or the atomic mass of an isotope, and then
@@ -286,7 +279,8 @@ def ion_mass(particle: Particle, *, Z: int = None,
     Raises
     ------
     `TypeError`
-        The argument is not a string, integer, or Particle.
+        The argument is not a `str`, `int`, or
+        `plasmapy.utils.~Particle`.
 
     `~plasmapy.utils.InvalidParticleError`
         If the arguments do not correspond to a valid particle.
@@ -328,8 +322,6 @@ def ion_mass(particle: Particle, *, Z: int = None,
 
     Examples
     --------
-    >>> print(ion_mass('p').si.value)
-    1.672621898e-27
     >>> ion_mass('H+')  # assumes terrestrial abundance of D
     <Quantity 1.67291241e-27 kg>
     >>> ion_mass('H+') == ion_mass('p')
@@ -344,8 +336,6 @@ def ion_mass(particle: Particle, *, Z: int = None,
     <Quantity 9.28812345e-26 kg>
     >>> ion_mass('Fe-56 1+')
     <Quantity 9.28812345e-26 kg>
-    >>> ion_mass('e+')
-    <<class 'astropy.constants.codata2014.CODATA2014'> name='Electron mass' value=9.10938356e-31 uncertainty=1.1e-38 unit='kg' reference='CODATA 2014'>
 
     """
 
@@ -356,8 +346,7 @@ def ion_mass(particle: Particle, *, Z: int = None,
     elif particle.particle == 'n':
         raise InvalidIonError
     elif particle.isotope in ['H-1']:
-        warnings.warn("Use 'p+' instead of 'H-1' to refer to protons",
-                      DeprecationWarning)
+        warnings.warn("Use 'p+' instead of 'H-1' to refer to protons", DeprecationWarning)
         return const.m_p
     elif particle.element:
         warnings.warn("The assumption that particles are singly ionized in"
@@ -372,8 +361,7 @@ def ion_mass(particle: Particle, *, Z: int = None,
 
 
 @particle_input(exclude={'neutrino', 'antineutrino'})
-def particle_mass(particle: Particle, *, Z: int = None,
-                  mass_numb: int = None) -> u.Quantity:
+def particle_mass(particle: Particle, *, Z: int = None, mass_numb: int = None) -> u.Quantity:
     """
     Return the mass of a particle.
 
@@ -435,8 +423,7 @@ def particle_mass(particle: Particle, *, Z: int = None,
 
 
 @particle_input
-def isotopic_abundance(isotope: Particle,
-                       mass_numb: int = None) -> u.Quantity:
+def isotopic_abundance(isotope: Particle, mass_numb: int = None) -> u.Quantity:
     """
     Return the isotopic abundances if known, and otherwise zero.
 
@@ -465,7 +452,7 @@ def isotopic_abundance(isotope: Particle,
         or contradictory information is provided.
 
     `TypeError`
-        If the argument is not a string or integer.
+        If the argument is not a `str` or `int`.
 
     Notes
     -----
@@ -482,8 +469,6 @@ def isotopic_abundance(isotope: Particle,
     0.524
     >>> isotopic_abundance('hydrogen', 1)
     0.999885
-    >>> isotopic_abundance(118, 294)  # Og-294
-    0.0
 
     """
     return isotope.isotopic_abundance
@@ -628,7 +613,7 @@ def is_stable(particle: Particle, mass_numb: int = None) -> bool:
         If the arguments do not correspond to a valid particle.
 
     `TypeError`
-        If the argument is not a string or integer.
+        If the argument is not a `str` or `int`.
 
     `~plasmapy.utils.MissingAtomicDataError`
         If stability information is not available.
@@ -647,8 +632,7 @@ def is_stable(particle: Particle, mass_numb: int = None) -> bool:
     """
     if particle.element and not particle.isotope:
         raise InvalidIsotopeError(
-            "The input to is_stable must be either an isotope or a "
-            "special particle."
+            "The input to is_stable must be either an isotope or a special particle."
         )
     return particle.is_category('stable')
 
@@ -684,8 +668,8 @@ def half_life(particle: Particle, mass_numb: int = None) -> u.Quantity:
         If no half-life data is available for the isotope.
 
     `TypeError`
-        The argument is not an integer or string or the mass number is
-        not an integer.
+        The argument is not an `int` or `str` or the mass number is
+        not an `int`.
 
     Notes
     -----
@@ -738,7 +722,7 @@ def known_isotopes(argument: Union[str, int] = None) -> List[str]:
         If the argument does not correspond to a valid particle.
 
     `TypeError`
-        If the argument is not a string or integer.
+        If the argument is not a `str` or `int`.
 
     Notes
     -----
@@ -798,8 +782,7 @@ def known_isotopes_for_element(argument):
     return isotopes_list
 
 
-def common_isotopes(argument: Union[str, int] = None,
-                    most_common_only: bool = False) -> List[str]:
+def common_isotopes(argument: Union[str, int] = None, most_common_only: bool = False) -> List[str]:
     """
     Return a list of isotopes of an element with an isotopic abundances
     greater than zero, or if no input is provided, a list of all such
@@ -816,7 +799,7 @@ def common_isotopes(argument: Union[str, int] = None,
 
     Returns
     -------
-    isotopes_list: list of strings or empty list
+    isotopes_list: `list` of `str` or empty `list`
         List of all isotopes of an element with isotopic abundances
         greater than zero, sorted from most abundant to least
         abundant.  If no isotopes have isotopic abundances greater
@@ -877,12 +860,18 @@ def common_isotopes_for_element(
             most_common_only: Optional[bool]) -> List[str]:
 
         isotopes = known_isotopes(argument)
-        CommonIsotopes = [isotope for isotope in isotopes if
-                          'abundance' in _Isotopes[isotope].keys()]
-        isotopic_abundances = [_Isotopes[isotope]['abundance']
-                               for isotope in CommonIsotopes]
-        sorted_isotopes = [iso_comp for (isotope, iso_comp) in
-                           sorted(zip(isotopic_abundances, CommonIsotopes))]
+
+        CommonIsotopes = [
+            isotope for isotope in isotopes if 'abundance' in _Isotopes[isotope].keys()
+        ]
+
+        isotopic_abundances = [
+            _Isotopes[isotope]['abundance'] for isotope in CommonIsotopes
+        ]
+
+        sorted_isotopes = [
+            iso_comp for (isotope, iso_comp) in sorted(zip(isotopic_abundances, CommonIsotopes))
+        ]
 
         sorted_isotopes.reverse()
 
@@ -895,8 +884,7 @@ def common_isotopes_for_element(
 
         try:
             element = atomic_symbol(argument)
-            isotopes_list = \
-                common_isotopes_for_element(element, most_common_only)
+            isotopes_list = common_isotopes_for_element(element, most_common_only)
         except InvalidParticleError:
             raise InvalidParticleError("Invalid particle")
         except InvalidElementError:
@@ -907,8 +895,7 @@ def common_isotopes_for_element(
     elif argument is None:
         isotopes_list = []
         for atomic_numb in range(1, 119):
-            isotopes_list += \
-                common_isotopes_for_element(atomic_numb, most_common_only)
+            isotopes_list += common_isotopes_for_element(atomic_numb, most_common_only)
 
     return isotopes_list
 
@@ -996,8 +983,7 @@ def stable_isotopes_for_element(argument: Union[str, int],
     if argument is not None:
         try:
             element = atomic_symbol(argument)
-            isotopes_list = \
-                stable_isotopes_for_element(element, not unstable)
+            isotopes_list = stable_isotopes_for_element(element, not unstable)
         except InvalidParticleError:
             raise InvalidParticleError("Invalid particle in stable_isotopes")
         except InvalidElementError:
@@ -1007,8 +993,7 @@ def stable_isotopes_for_element(argument: Union[str, int],
     elif argument is None:
         isotopes_list = []
         for atomic_numb in range(1, 119):
-            isotopes_list += \
-                stable_isotopes_for_element(atomic_numb, not unstable)
+            isotopes_list += stable_isotopes_for_element(atomic_numb, not unstable)
 
     return isotopes_list
 
@@ -1022,10 +1007,10 @@ def reduced_mass(test_particle, target_particle) -> u.Quantity:
     test_particle, target_particle : `str`, `int`, `~plasmapy.atomic.Particle`,
     `~astropy.units.Quantity`, or `~astropy.constants.Constant`
 
-        The test particle as represented by a string, an integer representing
-        atomic number, a `~plasmapy.atomic.Particle` object, or a
-        `~astropy.units.Quantity` or `~astropy.constants.Constant` with
-        units of mass.
+        The test particle as represented by a string, an integer
+        representing atomic number, a `~plasmapy.atomic.Particle`
+        object, or a `~astropy.units.Quantity` or
+        `~astropy.constants.Constant` with units of mass.
 
     Return
     -------
@@ -1045,8 +1030,9 @@ def reduced_mass(test_particle, target_particle) -> u.Quantity:
         If the mass of either particle is not known.
 
     `TypeError`
-        If either argument is not a `str`, `int`, `~plasmapy.atomic.Particle`,
-        `~astropy.units.Quantity`, or `~astropy.constants.Constant`.
+        If either argument is not a `str`, `int`,
+        `~plasmapy.atomic.Particle`, `~astropy.units.Quantity`, or
+        `~astropy.constants.Constant`.
 
     Example
     -------
@@ -1076,8 +1062,7 @@ def get_particle_mass(particle) -> u.Quantity:
                 particle = Particle(particle)
             return particle.mass.to(u.kg)
         except u.UnitConversionError as exc1:
-            raise u.UnitConversionError(
-                f"Incorrect units in reduced_mass.") from exc1
+            raise u.UnitConversionError(f"Incorrect units in reduced_mass.") from exc1
         except MissingAtomicDataError:
             raise MissingAtomicDataError(
                 f"Unable to find the reduced mass because the mass of "
@@ -1107,7 +1092,7 @@ def periodic_table_period(argument: Union[str, int]) -> int:
     Raises
     ------
     `TypeError`
-        If the argument is not a string or integer.
+        If the argument is not a `str` or `int`.
 
     See Also
     --------
@@ -1131,10 +1116,10 @@ def periodic_table_period(argument: Union[str, int]) -> int:
     """
     # TODO: Implement @particle_input
     if not isinstance(argument, (str, int)):
-        raise TypeError("The argument to periodic_table_period must be " +
-                        "either a string representing the element or its " +
-                        "symbol, or an integer representing its atomic " +
-                        "number.")
+        raise TypeError(
+            "The argument to periodic_table_period must be either a "
+            "string representing the element or its symbol, or an "
+            "integer representing its atomic number.")
     symbol = atomic_symbol(argument)
     period = _Elements[symbol]["period"]
     return period
@@ -1158,7 +1143,7 @@ def periodic_table_group(argument: Union[str, int]) -> int:
     Raises
     ------
     `TypeError`
-        If the argument is not a string or integer.
+        If the argument is not a `str` or `int`.
 
     See Also
     --------
@@ -1187,10 +1172,10 @@ def periodic_table_group(argument: Union[str, int]) -> int:
     """
     # TODO: Implement @particle_input
     if not isinstance(argument, (str, int)):
-        raise TypeError("The argument to periodic_table_group must be " +
-                        "either a string representing the element or its " +
-                        "symbol, or an integer representing its atomic " +
-                        "number.")
+        raise TypeError(
+            "The argument to periodic_table_group must be "
+            "either a string representing the element or its "
+            "symbol, or an integer representing its atomic number.")
     symbol = atomic_symbol(argument)
     group = _Elements[symbol]["group"]
     return group
@@ -1214,7 +1199,7 @@ def periodic_table_block(argument: Union[str, int]) -> str:
     Raises
     ------
     `TypeError`
-        If the argument is not a string or integer.
+        If the argument is not a `str` or `int`.
 
     See Also
     --------
@@ -1243,10 +1228,10 @@ def periodic_table_block(argument: Union[str, int]) -> str:
     """
     # TODO: Implement @particle_input
     if not isinstance(argument, (str, int)):
-        raise TypeError("The argument to periodic_table_block must be " +
-                        "either a string representing the element or its " +
-                        "symbol, or an integer representing its atomic " +
-                        "number.")
+        raise TypeError(
+            "The argument to periodic_table_block must be "
+            "either a string representing the element or its "
+            "symbol, or an integer representing its atomic number.")
     symbol = atomic_symbol(argument)
     block = _Elements[symbol]["block"]
     return block
@@ -1270,7 +1255,7 @@ def periodic_table_category(argument: Union[str, int]) -> str:
     Raises
     ------
     `TypeError`
-        If the argument is not a string or integer.
+        If the argument is not a `str` or `int`.
 
     See Also
     --------
@@ -1297,10 +1282,10 @@ def periodic_table_category(argument: Union[str, int]) -> str:
     """
     # TODO: Implement @particle_input
     if not isinstance(argument, (str, int)):
-        raise TypeError("The argument to periodic_table_category must be " +
-                        "either a string representing the element or its " +
-                        "symbol, or an integer representing its atomic " +
-                        "number.")
+        raise TypeError(
+            "The argument to periodic_table_category must be "
+            "either a string representing the element or its "
+            "symbol, or an integer representing its atomic number.")
     symbol = atomic_symbol(argument)
     category = _Elements[symbol]["category"]
     return category
diff --git a/plasmapy/atomic/elements.py b/plasmapy/atomic/elements.py
index bcd5862f..35ec29e0 100644
--- a/plasmapy/atomic/elements.py
+++ b/plasmapy/atomic/elements.py
@@ -4,259 +4,19 @@
 The periodic tabla data is from: http://periodic.lanl.gov/index.shtml
 """
 
-from astropy import units as u
-
-_atomic_symbols = {
-    1: "H",
-    2: "He",
-    3: "Li",
-    4: "Be",
-    5: "B",
-    6: "C",
-    7: "N",
-    8: "O",
-    9: "F",
-    10: "Ne",
-    11: "Na",
-    12: "Mg",
-    13: "Al",
-    14: "Si",
-    15: "P",
-    16: "S",
-    17: "Cl",
-    18: "Ar",
-    19: "K",
-    20: "Ca",
-    21: "Sc",
-    22: "Ti",
-    23: "V",
-    24: "Cr",
-    25: "Mn",
-    26: "Fe",
-    27: "Co",
-    28: "Ni",
-    29: "Cu",
-    30: "Zn",
-    31: "Ga",
-    32: "Ge",
-    33: "As",
-    34: "Se",
-    35: "Br",
-    36: "Kr",
-    37: "Rb",
-    38: "Sr",
-    39: "Y",
-    40: "Zr",
-    41: "Nb",
-    42: "Mo",
-    43: "Tc",
-    44: "Ru",
-    45: "Rh",
-    46: "Pd",
-    47: "Ag",
-    48: "Cd",
-    49: "In",
-    50: "Sn",
-    51: "Sb",
-    52: "Te",
-    53: "I",
-    54: "Xe",
-    55: "Cs",
-    56: "Ba",
-    57: "La",
-    58: "Ce",
-    59: "Pr",
-    60: "Nd",
-    61: "Pm",
-    62: "Sm",
-    63: "Eu",
-    64: "Gd",
-    65: "Tb",
-    66: "Dy",
-    67: "Ho",
-    68: "Er",
-    69: "Tm",
-    70: "Yb",
-    71: "Lu",
-    72: "Hf",
-    73: "Ta",
-    74: "W",
-    75: "Re",
-    76: "Os",
-    77: "Ir",
-    78: "Pt",
-    79: "Au",
-    80: "Hg",
-    81: "Tl",
-    82: "Pb",
-    83: "Bi",
-    84: "Po",
-    85: "At",
-    86: "Rn",
-    87: "Fr",
-    88: "Ra",
-    89: "Ac",
-    90: "Th",
-    91: "Pa",
-    92: "U",
-    93: "Np",
-    94: "Pu",
-    95: "Am",
-    96: "Cm",
-    97: "Bk",
-    98: "Cf",
-    99: "Es",
-    100: "Fm",
-    101: "Md",
-    102: "No",
-    103: "Lr",
-    104: "Rf",
-    105: "Db",
-    106: "Sg",
-    107: "Bh",
-    108: "Hs",
-    109: "Mt",
-    110: "Ds",
-    111: "Rg",
-    112: "Cn",
-    113: "Nh",
-    114: "Fl",
-    115: "Mc",
-    116: "Lv",
-    117: "Ts",
-    118: "Og",
-}
-
-
-_atomic_symbols_dict = {
-    'hydrogen': "H",
-    'helium': "He",
-    'lithium': "Li",
-    'beryllium': "Be",
-    'boron': "B",
-    'carbon': "C",
-    'nitrogen': "N",
-    'oxygen': "O",
-    'fluorine': "F",
-    'neon': "Ne",
-    'sodium': "Na",
-    'magnesium': "Mg",
-    'aluminium': "Al",
-    'silicon': "Si",
-    'phosphorus': "P",
-    'sulfur': "S",
-    'chlorine': "Cl",
-    'argon': "Ar",
-    'potassium': "K",
-    'calcium': "Ca",
-    'scandium': "Sc",
-    'titanium': "Ti",
-    'vanadium': "V",
-    'chromium': "Cr",
-    'manganese': "Mn",
-    'iron': "Fe",
-    'cobalt': "Co",
-    'nickel': "Ni",
-    'copper': "Cu",
-    'zinc': "Zn",
-    'gallium': "Ga",
-    'germanium': "Ge",
-    'arsenic': "As",
-    'selenium': "Se",
-    'bromine': "Br",
-    'krypton': "Kr",
-    'rubidium': "Rb",
-    'strontium': "Sr",
-    'yttrium': "Y",
-    'zirconium': "Zr",
-    'niobium': "Nb",
-    'molybdenum': "Mo",
-    'technetium': "Tc",
-    'ruthenium': "Ru",
-    'rhodium': "Rh",
-    'palladium': "Pd",
-    'silver': "Ag",
-    'cadmium': "Cd",
-    'indium': "In",
-    'tin': "Sn",
-    'antimony': "Sb",
-    'tellurium': "Te",
-    'iodine': "I",
-    'xenon': "Xe",
-    'caesium': "Cs",
-    'barium': "Ba",
-    'lanthanum': "La",
-    'cerium': "Ce",
-    'praseodymium': "Pr",
-    'neodymium': "Nd",
-    'promethium': "Pm",
-    'samarium': "Sm",
-    'europium': "Eu",
-    'gadolinium': "Gd",
-    'terbium': "Tb",
-    'dysprosium': "Dy",
-    'holmium': "Ho",
-    'erbium': "Er",
-    'thulium': "Tm",
-    'ytterbium': "Yb",
-    'lutetium': "Lu",
-    'hafnium': "Hf",
-    'tantalum': "Ta",
-    'tungsten': "W",
-    'rhenium': "Re",
-    'osmium': "Os",
-    'iridium': "Ir",
-    'platinum': "Pt",
-    'gold': "Au",
-    'mercury': "Hg",
-    'thallium': "Tl",
-    'lead': "Pb",
-    'bismuth': "Bi",
-    'polonium': "Po",
-    'astatine': "At",
-    'radon': "Rn",
-    'francium': "Fr",
-    'radium': "Ra",
-    'actinium': "Ac",
-    'thorium': "Th",
-    'protactinium': "Pa",
-    'uranium': "U",
-    'neptunium': "Np",
-    'plutonium': "Pu",
-    'americium': "Am",
-    'curium': "Cm",
-    'berkelium': "Bk",
-    'californium': "Cf",
-    'einsteinium': "Es",
-    'fermium': "Fm",
-    'mendelevium': "Md",
-    'nobelium': "No",
-    'lawrencium': "Lr",
-    'rutherfordium': "Rf",
-    'dubnium': "Db",
-    'seaborgium': "Sg",
-    'bohrium': "Bh",
-    'hassium': "Hs",
-    'meitnerium': "Mt",
-    'darmstadtium': "Ds",
-    'roentgenium': "Rg",
-    'copernicium': "Cn",
-    'nihonium': "Nh",
-    'flerovium': "Fl",
-    'moscovium': "Mc",
-    'livermorium': "Lv",
-    'tennessine': "Ts",
-    'oganesson': "Og",
-}
+import collections
+import astropy.units as u
 
+_PeriodicTable = collections.namedtuple(
+    "periodic_table", ['group', 'category', 'block', 'period']
+)
 
 _Elements = {
 
     "H": {
-        "atomic_number": 1,
-        "symbol": "H",
-        "atomic_mass": 1.008 * u.u,
-        "name": "hydrogen",
+        "atomic number": 1,
+        "atomic mass": 1.008 * u.u,
+        "element name": "hydrogen",
         "period": 1,
         "group": 1,
         "block": "s",
@@ -264,10 +24,9 @@
     },
 
     "He": {
-        "atomic_number": 2,
-        "symbol": "He",
-        "atomic_mass": 4.002602 * u.u,
-        "name": "helium",
+        "atomic number": 2,
+        "atomic mass": 4.002602 * u.u,
+        "element name": "helium",
         "period": 1,
         "group": 18,
         "block": "s",
@@ -275,10 +34,9 @@
     },
 
     "Li": {
-        "atomic_number": 3,
-        "symbol": "Li",
-        "atomic_mass": 6.94 * u.u,
-        "name": "lithium",
+        "atomic number": 3,
+        "atomic mass": 6.94 * u.u,
+        "element name": "lithium",
         "period": 2,
         "group": 1,
         "block": "s",
@@ -286,10 +44,9 @@
     },
 
     "Be": {
-        "atomic_number": 4,
-        "symbol": "Be",
-        "atomic_mass": 9.0121831 * u.u,
-        "name": "beryllium",
+        "atomic number": 4,
+        "atomic mass": 9.0121831 * u.u,
+        "element name": "beryllium",
         "period": 2,
         "group": 2,
         "block": "s",
@@ -297,10 +54,9 @@
     },
 
     "B": {
-        "atomic_number": 5,
-        "symbol": "B",
-        "atomic_mass": 10.806 * u.u,
-        "name": "boron",
+        "atomic number": 5,
+        "atomic mass": 10.806 * u.u,
+        "element name": "boron",
         "period": 2,
         "group": 13,
         "block": "p",
@@ -308,10 +64,9 @@
     },
 
     "C": {
-        "atomic_number": 6,
-        "symbol": "C",
-        "atomic_mass": 12.011 * u.u,
-        "name": "carbon",
+        "atomic number": 6,
+        "atomic mass": 12.011 * u.u,
+        "element name": "carbon",
         "period": 2,
         "group": 14,
         "block": "p",
@@ -319,10 +74,9 @@
     },
 
     "N": {
-        "atomic_number": 7,
-        "symbol": "N",
-        "atomic_mass": 14.007 * u.u,
-        "name": "nitrogen",
+        "atomic number": 7,
+        "atomic mass": 14.007 * u.u,
+        "element name": "nitrogen",
         "period": 2,
         "group": 15,
         "block": "p",
@@ -330,10 +84,9 @@
     },
 
     "O": {
-        "atomic_number": 8,
-        "symbol": "O",
-        "atomic_mass": 15.999 * u.u,
-        "name": "oxygen",
+        "atomic number": 8,
+        "atomic mass": 15.999 * u.u,
+        "element name": "oxygen",
         "period": 2,
         "group": 16,
         "block": "p",
@@ -341,10 +94,9 @@
     },
 
     "F": {
-        "atomic_number": 9,
-        "symbol": "F",
-        "atomic_mass": 18.998403163 * u.u,
-        "name": "fluorine",
+        "atomic number": 9,
+        "atomic mass": 18.998403163 * u.u,
+        "element name": "fluorine",
         "period": 2,
         "group": 17,
         "block": "p",
@@ -352,10 +104,9 @@
     },
 
     "Ne": {
-        "atomic_number": 10,
-        "symbol": "Ne",
-        "atomic_mass": 20.1797 * u.u,
-        "name": "neon",
+        "atomic number": 10,
+        "atomic mass": 20.1797 * u.u,
+        "element name": "neon",
         "period": 2,
         "group": 18,
         "block": "p",
@@ -363,10 +114,9 @@
     },
 
     "Na": {
-        "atomic_number": 11,
-        "symbol": "Na",
-        "atomic_mass": 22.98976928 * u.u,
-        "name": "sodium",
+        "atomic number": 11,
+        "atomic mass": 22.98976928 * u.u,
+        "element name": "sodium",
         "period": 3,
         "group": 1,
         "block": "s",
@@ -374,10 +124,9 @@
     },
 
     "Mg": {
-        "atomic_number": 12,
-        "symbol": "Mg",
-        "atomic_mass": 24.305 * u.u,
-        "name": "magnesium",
+        "atomic number": 12,
+        "atomic mass": 24.305 * u.u,
+        "element name": "magnesium",
         "period": 3,
         "group": 2,
         "block": "s",
@@ -385,10 +134,9 @@
     },
 
     "Al": {
-        "atomic_number": 13,
-        "symbol": "Al",
-        "atomic_mass": 26.9815385 * u.u,
-        "name": "aluminium",
+        "atomic number": 13,
+        "atomic mass": 26.9815385 * u.u,
+        "element name": "aluminium",
         "period": 3,
         "group": 13,
         "block": "p",
@@ -396,10 +144,9 @@
     },
 
     "Si": {
-        "atomic_number": 14,
-        "symbol": "Si",
-        "atomic_mass": 28.085 * u.u,
-        "name": "silicon",
+        "atomic number": 14,
+        "atomic mass": 28.085 * u.u,
+        "element name": "silicon",
         "period": 3,
         "group": 14,
         "block": "p",
@@ -407,10 +154,9 @@
     },
 
     "P": {
-        "atomic_number": 15,
-        "symbol": "P",
-        "atomic_mass": 30.973761998 * u.u,
-        "name": "phosphorus",
+        "atomic number": 15,
+        "atomic mass": 30.973761998 * u.u,
+        "element name": "phosphorus",
         "period": 3,
         "group": 15,
         "block": "p",
@@ -418,10 +164,10 @@
     },
 
     "S": {
-        "atomic_number": 16,
+        "atomic number": 16,
         "symbol": "S",
-        "atomic_mass": 32.06 * u.u,
-        "name": "sulfur",
+        "atomic mass": 32.06 * u.u,
+        "element name": "sulfur",
         "period": 3,
         "group": 16,
         "block": "p",
@@ -429,10 +175,9 @@
     },
 
     "Cl": {
-        "atomic_number": 17,
-        "symbol": "Cl",
-        "atomic_mass": 35.45 * u.u,
-        "name": "chlorine",
+        "atomic number": 17,
+        "atomic mass": 35.45 * u.u,
+        "element name": "chlorine",
         "period": 3,
         "group": 17,
         "block": "p",
@@ -440,10 +185,9 @@
     },
 
     "Ar": {
-        "atomic_number": 18,
-        "symbol": "Ar",
-        "atomic_mass": 39.948 * u.u,
-        "name": "argon",
+        "atomic number": 18,
+        "atomic mass": 39.948 * u.u,
+        "element name": "argon",
         "period": 3,
         "group": 18,
         "block": "p",
@@ -451,10 +195,9 @@
     },
 
     "K": {
-        "atomic_number": 19,
-        "symbol": "K",
-        "atomic_mass": 39.0983 * u.u,
-        "name": "potassium",
+        "atomic number": 19,
+        "atomic mass": 39.0983 * u.u,
+        "element name": "potassium",
         "period": 4,
         "group": 1,
         "block": "s",
@@ -462,10 +205,9 @@
     },
 
     "Ca": {
-        "atomic_number": 20,
-        "symbol": "Ca",
-        "atomic_mass": 40.078 * u.u,
-        "name": "calcium",
+        "atomic number": 20,
+        "atomic mass": 40.078 * u.u,
+        "element name": "calcium",
         "period": 4,
         "group": 2,
         "block": "s",
@@ -473,10 +215,9 @@
     },
 
     "Sc": {
-        "atomic_number": 21,
-        "symbol": "Sc",
-        "atomic_mass": 44.955908 * u.u,
-        "name": "scandium",
+        "atomic number": 21,
+        "atomic mass": 44.955908 * u.u,
+        "element name": "scandium",
         "period": 4,
         "group": 3,
         "block": "d",
@@ -484,10 +225,9 @@
     },
 
     "Ti": {
-        "atomic_number": 22,
-        "symbol": "Ti",
-        "atomic_mass": 47.867 * u.u,
-        "name": "titanium",
+        "atomic number": 22,
+        "atomic mass": 47.867 * u.u,
+        "element name": "titanium",
         "period": 4,
         "group": 4,
         "block": "d",
@@ -495,10 +235,9 @@
     },
 
     "V": {
-        "atomic_number": 23,
-        "symbol": "V",
-        "atomic_mass": 50.9415 * u.u,
-        "name": "vanadium",
+        "atomic number": 23,
+        "atomic mass": 50.9415 * u.u,
+        "element name": "vanadium",
         "period": 4,
         "group": 5,
         "block": "d",
@@ -506,10 +245,9 @@
     },
 
     "Cr": {
-        "atomic_number": 24,
-        "symbol": "Cr",
-        "atomic_mass": 51.9961 * u.u,
-        "name": "chromium",
+        "atomic number": 24,
+        "atomic mass": 51.9961 * u.u,
+        "element name": "chromium",
         "period": 4,
         "group": 6,
         "block": "d",
@@ -517,10 +255,9 @@
     },
 
     "Mn": {
-        "atomic_number": 25,
-        "symbol": "Mn",
-        "atomic_mass": 54.938044 * u.u,
-        "name": "manganese",
+        "atomic number": 25,
+        "atomic mass": 54.938044 * u.u,
+        "element name": "manganese",
         "period": 4,
         "group": 7,
         "block": "d",
@@ -528,10 +265,9 @@
     },
 
     "Fe": {
-        "atomic_number": 26,
-        "symbol": "Fe",
-        "atomic_mass": 55.845 * u.u,
-        "name": "iron",
+        "atomic number": 26,
+        "atomic mass": 55.845 * u.u,
+        "element name": "iron",
         "period": 4,
         "group": 8,
         "block": "d",
@@ -539,10 +275,9 @@
     },
 
     "Co": {
-        "atomic_number": 27,
-        "symbol": "Co",
-        "atomic_mass": 58.933 * u.u,
-        "name": "cobalt",
+        "atomic number": 27,
+        "atomic mass": 58.933 * u.u,
+        "element name": "cobalt",
         "period": 4,
         "group": 9,
         "block": "d",
@@ -550,10 +285,9 @@
     },
 
     "Ni": {
-        "atomic_number": 28,
-        "symbol": "Ni",
-        "atomic_mass": 58.6934 * u.u,
-        "name": "nickel",
+        "atomic number": 28,
+        "atomic mass": 58.6934 * u.u,
+        "element name": "nickel",
         "period": 4,
         "group": 10,
         "block": "d",
@@ -561,10 +295,9 @@
     },
 
     "Cu": {
-        "atomic_number": 29,
-        "symbol": "Cu",
-        "atomic_mass": 63.546 * u.u,
-        "name": "copper",
+        "atomic number": 29,
+        "atomic mass": 63.546 * u.u,
+        "element name": "copper",
         "period": 4,
         "group": 11,
         "block": "d",
@@ -572,10 +305,9 @@
     },
 
     "Zn": {
-        "atomic_number": 30,
-        "symbol": "Zn",
-        "atomic_mass": 65.38 * u.u,
-        "name": "zinc",
+        "atomic number": 30,
+        "atomic mass": 65.38 * u.u,
+        "element name": "zinc",
         "period": 4,
         "group": 12,
         "block": "d",
@@ -583,10 +315,9 @@
     },
 
     "Ga": {
-        "atomic_number": 31,
-        "symbol": "Ga",
-        "atomic_mass": 69.723 * u.u,
-        "name": "gallium",
+        "atomic number": 31,
+        "atomic mass": 69.723 * u.u,
+        "element name": "gallium",
         "period": 4,
         "group": 13,
         "block": "p",
@@ -594,10 +325,9 @@
     },
 
     "Ge": {
-        "atomic_number": 32,
-        "symbol": "Ge",
-        "atomic_mass": 72.630 * u.u,
-        "name": "germanium",
+        "atomic number": 32,
+        "atomic mass": 72.630 * u.u,
+        "element name": "germanium",
         "period": 4,
         "group": 14,
         "block": "p",
@@ -605,10 +335,9 @@
     },
 
     "As": {
-        "atomic_number": 33,
-        "symbol": "As",
-        "atomic_mass": 74.921595 * u.u,
-        "name": "arsenic",
+        "atomic number": 33,
+        "atomic mass": 74.921595 * u.u,
+        "element name": "arsenic",
         "period": 4,
         "group": 15,
         "block": "p",
@@ -616,10 +345,9 @@
     },
 
     "Se": {
-        "atomic_number": 34,
-        "symbol": "Se",
-        "atomic_mass": 78.971 * u.u,
-        "name": "selenium",
+        "atomic number": 34,
+        "atomic mass": 78.971 * u.u,
+        "element name": "selenium",
         "period": 4,
         "group": 16,
         "block": "p",
@@ -627,10 +355,9 @@
     },
 
     "Br": {
-        "atomic_number": 35,
-        "symbol": "Br",
-        "atomic_mass": 79.904 * u.u,
-        "name": "bromine",
+        "atomic number": 35,
+        "atomic mass": 79.904 * u.u,
+        "element name": "bromine",
         "period": 4,
         "group": 17,
         "block": "p",
@@ -638,10 +365,9 @@
     },
 
     "Kr": {
-        "atomic_number": 36,
-        "symbol": "Kr",
-        "atomic_mass": 83.798 * u.u,
-        "name": "krypton",
+        "atomic number": 36,
+        "atomic mass": 83.798 * u.u,
+        "element name": "krypton",
         "period": 4,
         "group": 18,
         "block": "p",
@@ -649,10 +375,9 @@
     },
 
     "Rb": {
-        "atomic_number": 37,
-        "symbol": "Rb",
-        "atomic_mass": 85.4678 * u.u,
-        "name": "rubidium",
+        "atomic number": 37,
+        "atomic mass": 85.4678 * u.u,
+        "element name": "rubidium",
         "period": 5,
         "group": 1,
         "block": "s",
@@ -660,10 +385,9 @@
     },
 
     "Sr": {
-        "atomic_number": 38,
-        "symbol": "Sr",
-        "atomic_mass": 87.62 * u.u,
-        "name": "strontium",
+        "atomic number": 38,
+        "atomic mass": 87.62 * u.u,
+        "element name": "strontium",
         "period": 5,
         "group": 2,
         "block": "s",
@@ -671,10 +395,9 @@
     },
 
     "Y": {
-        "atomic_number": 39,
-        "symbol": "Y",
-        "atomic_mass": 88.90584 * u.u,
-        "name": "yttrium",
+        "atomic number": 39,
+        "atomic mass": 88.90584 * u.u,
+        "element name": "yttrium",
         "period": 5,
         "group": 3,
         "block": "d",
@@ -682,10 +405,9 @@
     },
 
     "Zr": {
-        "atomic_number": 40,
-        "symbol": "Zr",
-        "atomic_mass": 91.224 * u.u,
-        "name": "zirconium",
+        "atomic number": 40,
+        "atomic mass": 91.224 * u.u,
+        "element name": "zirconium",
         "period": 5,
         "group": 4,
         "block": "d",
@@ -693,10 +415,9 @@
     },
 
     "Nb": {
-        "atomic_number": 41,
-        "symbol": "Nb",
-        "atomic_mass": 92.90637 * u.u,
-        "name": "niobium",
+        "atomic number": 41,
+        "atomic mass": 92.90637 * u.u,
+        "element name": "niobium",
         "period": 5,
         "group": 5,
         "block": "d",
@@ -704,10 +425,9 @@
     },
 
     "Mo": {
-        "atomic_number": 42,
-        "symbol": "Mo",
-        "atomic_mass": 95.95 * u.u,
-        "name": "molybdenum",
+        "atomic number": 42,
+        "atomic mass": 95.95 * u.u,
+        "element name": "molybdenum",
         "period": 5,
         "group": 6,
         "block": "d",
@@ -715,9 +435,8 @@
     },
 
     "Tc": {
-        "atomic_number": 43,
-        "symbol": "Tc",
-        "name": "technetium",
+        "atomic number": 43,
+        "element name": "technetium",
         "period": 5,
         "group": 7,
         "block": "d",
@@ -725,10 +444,9 @@
     },
 
     "Ru": {
-        "atomic_number": 44,
-        "symbol": "Ru",
-        "atomic_mass": 101.07 * u.u,
-        "name": "ruthenium",
+        "atomic number": 44,
+        "atomic mass": 101.07 * u.u,
+        "element name": "ruthenium",
         "period": 5,
         "group": 8,
         "block": "d",
@@ -736,10 +454,9 @@
     },
 
     "Rh": {
-        "atomic_number": 45,
-        "symbol": "Rh",
-        "atomic_mass": 102.90550 * u.u,
-        "name": "rhodium",
+        "atomic number": 45,
+        "atomic mass": 102.90550 * u.u,
+        "element name": "rhodium",
         "period": 5,
         "group": 9,
         "block": "d",
@@ -747,10 +464,9 @@
     },
 
     "Pd": {
-        "atomic_number": 46,
-        "symbol": "Pd",
-        "atomic_mass": 106.42 * u.u,
-        "name": "palladium",
+        "atomic number": 46,
+        "atomic mass": 106.42 * u.u,
+        "element name": "palladium",
         "period": 5,
         "group": 10,
         "block": "d",
@@ -758,10 +474,9 @@
     },
 
     "Ag": {
-        "atomic_number": 47,
-        "symbol": "Ag",
-        "atomic_mass": 107.8682 * u.u,
-        "name": "silver",
+        "atomic number": 47,
+        "atomic mass": 107.8682 * u.u,
+        "element name": "silver",
         "period": 5,
         "group": 11,
         "block": "d",
@@ -769,10 +484,9 @@
     },
 
     "Cd": {
-        "atomic_number": 48,
-        "symbol": "Cd",
-        "atomic_mass": 112.414 * u.u,
-        "name": "cadmium",
+        "atomic number": 48,
+        "atomic mass": 112.414 * u.u,
+        "element name": "cadmium",
         "period": 5,
         "group": 12,
         "block": "d",
@@ -780,10 +494,9 @@
     },
 
     "In": {
-        "atomic_number": 49,
-        "symbol": "In",
-        "atomic_mass": 114.818 * u.u,
-        "name": "indium",
+        "atomic number": 49,
+        "atomic mass": 114.818 * u.u,
+        "element name": "indium",
         "period": 5,
         "group": 13,
         "block": "p",
@@ -791,10 +504,9 @@
     },
 
     "Sn": {
-        "atomic_number": 50,
-        "symbol": "Sn",
-        "atomic_mass": 118.710 * u.u,
-        "name": "tin",
+        "atomic number": 50,
+        "atomic mass": 118.710 * u.u,
+        "element name": "tin",
         "period": 5,
         "group": 14,
         "block": "p",
@@ -802,10 +514,9 @@
     },
 
     "Sb": {
-        "atomic_number": 51,
-        "symbol": "Sb",
-        "atomic_mass": 121.760 * u.u,
-        "name": "antimony",
+        "atomic number": 51,
+        "atomic mass": 121.760 * u.u,
+        "element name": "antimony",
         "period": 5,
         "group": 15,
         "block": "p",
@@ -813,10 +524,9 @@
     },
 
     "Te": {
-        "atomic_number": 52,
-        "symbol": "Te",
-        "atomic_mass": 127.60 * u.u,
-        "name": "tellurium",
+        "atomic number": 52,
+        "atomic mass": 127.60 * u.u,
+        "element name": "tellurium",
         "period": 5,
         "group": 16,
         "block": "p",
@@ -824,10 +534,9 @@
     },
 
     "I": {
-        "atomic_number": 53,
-        "symbol": "I",
-        "atomic_mass": 126.90447 * u.u,
-        "name": "iodine",
+        "atomic number": 53,
+        "atomic mass": 126.90447 * u.u,
+        "element name": "iodine",
         "period": 5,
         "group": 17,
         "block": "p",
@@ -835,10 +544,9 @@
     },
 
     "Xe": {
-        "atomic_number": 54,
-        "symbol": "Xe",
-        "atomic_mass": 131.293 * u.u,
-        "name": "xenon",
+        "atomic number": 54,
+        "atomic mass": 131.293 * u.u,
+        "element name": "xenon",
         "period": 5,
         "group": 18,
         "block": "p",
@@ -846,10 +554,9 @@
     },
 
     "Cs": {
-        "atomic_number": 55,
-        "symbol": "Cs",
-        "atomic_mass": 132.90545196 * u.u,
-        "name": "caesium",
+        "atomic number": 55,
+        "atomic mass": 132.90545196 * u.u,
+        "element name": "caesium",
         "period": 6,
         "group": 1,
         "block": "s",
@@ -857,10 +564,9 @@
     },
 
     "Ba": {
-        "atomic_number": 56,
-        "symbol": "Ba",
-        "atomic_mass": 137.327 * u.u,
-        "name": "barium",
+        "atomic number": 56,
+        "atomic mass": 137.327 * u.u,
+        "element name": "barium",
         "period": 6,
         "group": 2,
         "block": "s",
@@ -868,10 +574,9 @@
     },
 
     "La": {
-        "atomic_number": 57,
-        "symbol": "La",
-        "atomic_mass": 138.90547 * u.u,
-        "name": "lanthanum",
+        "atomic number": 57,
+        "atomic mass": 138.90547 * u.u,
+        "element name": "lanthanum",
         "period": 6,
         "group": 3,
         "block": "d",
@@ -879,10 +584,9 @@
     },
 
     "Ce": {
-        "atomic_number": 58,
-        "symbol": "Ce",
-        "atomic_mass": 140.116 * u.u,
-        "name": "cerium",
+        "atomic number": 58,
+        "atomic mass": 140.116 * u.u,
+        "element name": "cerium",
         "period": 6,
         "group": 3,
         "block": "f",
@@ -890,10 +594,9 @@
     },
 
     "Pr": {
-        "atomic_number": 59,
-        "symbol": "Pr",
-        "atomic_mass": 140.90766 * u.u,
-        "name": "praseodymium",
+        "atomic number": 59,
+        "atomic mass": 140.90766 * u.u,
+        "element name": "praseodymium",
         "period": 6,
         "group": 3,
         "block": "f",
@@ -901,10 +604,9 @@
     },
 
     "Nd": {
-        "atomic_number": 60,
-        "symbol": "Nd",
-        "atomic_mass": 144.242 * u.u,
-        "name": "neodymium",
+        "atomic number": 60,
+        "atomic mass": 144.242 * u.u,
+        "element name": "neodymium",
         "period": 6,
         "group": 3,
         "block": "f",
@@ -912,9 +614,8 @@
     },
 
     "Pm": {
-        "atomic_number": 61,
-        "symbol": "Pm",
-        "name": "promethium",
+        "atomic number": 61,
+        "element name": "promethium",
         "period": 6,
         "group": 3,
         "block": "f",
@@ -922,10 +623,9 @@
     },
 
     "Sm": {
-        "atomic_number": 62,
-        "symbol": "Sm",
-        "atomic_mass": 150.36 * u.u,
-        "name": "samarium",
+        "atomic number": 62,
+        "atomic mass": 150.36 * u.u,
+        "element name": "samarium",
         "period": 6,
         "group": 3,
         "block": "f",
@@ -933,10 +633,9 @@
     },
 
     "Eu": {
-        "atomic_number": 63,
-        "symbol": "Eu",
-        "atomic_mass": 151.964 * u.u,
-        "name": "europium",
+        "atomic number": 63,
+        "atomic mass": 151.964 * u.u,
+        "element name": "europium",
         "period": 6,
         "group": 3,
         "block": "f",
@@ -944,10 +643,9 @@
     },
 
     "Gd": {
-        "atomic_number": 64,
-        "symbol": "Gd",
-        "atomic_mass": 157.25 * u.u,
-        "name": "gadolinium",
+        "atomic number": 64,
+        "atomic mass": 157.25 * u.u,
+        "element name": "gadolinium",
         "period": 6,
         "group": 3,
         "block": "f",
@@ -955,10 +653,9 @@
     },
 
     "Tb": {
-        "atomic_number": 65,
-        "symbol": "Tb",
-        "atomic_mass": 158.92535 * u.u,
-        "name": "terbium",
+        "atomic number": 65,
+        "atomic mass": 158.92535 * u.u,
+        "element name": "terbium",
         "period": 6,
         "group": 3,
         "block": "f",
@@ -966,10 +663,9 @@
     },
 
     "Dy": {
-        "atomic_number": 66,
-        "symbol": "Dy",
-        "atomic_mass": 162.500 * u.u,
-        "name": "dysprosium",
+        "atomic number": 66,
+        "atomic mass": 162.500 * u.u,
+        "element name": "dysprosium",
         "period": 6,
         "group": 3,
         "block": "f",
@@ -977,10 +673,9 @@
     },
 
     "Ho": {
-        "atomic_number": 67,
-        "symbol": "Ho",
-        "atomic_mass": 164.93033 * u.u,
-        "name": "holmium",
+        "atomic number": 67,
+        "atomic mass": 164.93033 * u.u,
+        "element name": "holmium",
         "period": 6,
         "group": 3,
         "block": "f",
@@ -988,10 +683,9 @@
     },
 
     "Er": {
-        "atomic_number": 68,
-        "symbol": "Er",
-        "atomic_mass": 167.259 * u.u,
-        "name": "erbium",
+        "atomic number": 68,
+        "atomic mass": 167.259 * u.u,
+        "element name": "erbium",
         "period": 6,
         "group": 3,
         "block": "f",
@@ -999,10 +693,9 @@
     },
 
     "Tm": {
-        "atomic_number": 69,
-        "symbol": "Tm",
-        "atomic_mass": 168.93422 * u.u,
-        "name": "thulium",
+        "atomic number": 69,
+        "atomic mass": 168.93422 * u.u,
+        "element name": "thulium",
         "period": 6,
         "group": 3,
         "block": "f",
@@ -1010,10 +703,9 @@
     },
 
     "Yb": {
-        "atomic_number": 70,
-        "symbol": "Yb",
-        "atomic_mass": 173.045 * u.u,
-        "name": "ytterbium",
+        "atomic number": 70,
+        "atomic mass": 173.045 * u.u,
+        "element name": "ytterbium",
         "period": 6,
         "group": 3,
         "block": "f",
@@ -1021,10 +713,9 @@
     },
 
     "Lu": {
-        "atomic_number": 71,
-        "symbol": "Lu",
-        "atomic_mass": 174.9668 * u.u,
-        "name": "lutetium",
+        "atomic number": 71,
+        "atomic mass": 174.9668 * u.u,
+        "element name": "lutetium",
         "period": 6,
         "group": 3,
         "block": "f",
@@ -1032,10 +723,9 @@
     },
 
     "Hf": {
-        "atomic_number": 72,
-        "symbol": "Hf",
-        "atomic_mass": 178.49 * u.u,
-        "name": "hafnium",
+        "atomic number": 72,
+        "atomic mass": 178.49 * u.u,
+        "element name": "hafnium",
         "period": 6,
         "group": 4,
         "block": "d",
@@ -1043,10 +733,9 @@
     },
 
     "Ta": {
-        "atomic_number": 73,
-        "symbol": "Ta",
-        "atomic_mass": 180.94788 * u.u,
-        "name": "tantalum",
+        "atomic number": 73,
+        "atomic mass": 180.94788 * u.u,
+        "element name": "tantalum",
         "period": 6,
         "group": 5,
         "block": "d",
@@ -1054,10 +743,9 @@
     },
 
     "W": {
-        "atomic_number": 74,
-        "symbol": "W",
-        "atomic_mass": 183.84 * u.u,
-        "name": "tungsten",
+        "atomic number": 74,
+        "atomic mass": 183.84 * u.u,
+        "element name": "tungsten",
         "period": 6,
         "group": 6,
         "block": "d",
@@ -1065,10 +753,9 @@
     },
 
     "Re": {
-        "atomic_number": 75,
-        "symbol": "Re",
-        "atomic_mass": 186.207 * u.u,
-        "name": "rhenium",
+        "atomic number": 75,
+        "atomic mass": 186.207 * u.u,
+        "element name": "rhenium",
         "period": 6,
         "group": 7,
         "block": "d",
@@ -1076,10 +763,9 @@
     },
 
     "Os": {
-        "atomic_number": 76,
-        "symbol": "Os",
-        "atomic_mass": 190.23 * u.u,
-        "name": "osmium",
+        "atomic number": 76,
+        "atomic mass": 190.23 * u.u,
+        "element name": "osmium",
         "period": 6,
         "group": 8,
         "block": "d",
@@ -1087,10 +773,9 @@
     },
 
     "Ir": {
-        "atomic_number": 77,
-        "symbol": "Ir",
-        "atomic_mass": 192.217 * u.u,
-        "name": "iridium",
+        "atomic number": 77,
+        "atomic mass": 192.217 * u.u,
+        "element name": "iridium",
         "period": 6,
         "group": 9,
         "block": "d",
@@ -1098,10 +783,9 @@
     },
 
     "Pt": {
-        "atomic_number": 78,
-        "symbol": "Pt",
-        "atomic_mass": 195.084 * u.u,
-        "name": "platinum",
+        "atomic number": 78,
+        "atomic mass": 195.084 * u.u,
+        "element name": "platinum",
         "period": 6,
         "group": 10,
         "block": "d",
@@ -1109,10 +793,9 @@
     },
 
     "Au": {
-        "atomic_number": 79,
-        "symbol": "Au",
-        "atomic_mass": 196.966569 * u.u,
-        "name": "gold",
+        "atomic number": 79,
+        "atomic mass": 196.966569 * u.u,
+        "element name": "gold",
         "period": 6,
         "group": 11,
         "block": "d",
@@ -1120,10 +803,9 @@
     },
 
     "Hg": {
-        "atomic_number": 80,
-        "symbol": "Hg",
-        "atomic_mass": 200.592 * u.u,
-        "name": "mercury",
+        "atomic number": 80,
+        "atomic mass": 200.592 * u.u,
+        "element name": "mercury",
         "period": 6,
         "group": 12,
         "block": "d",
@@ -1131,10 +813,9 @@
     },
 
     "Tl": {
-        "atomic_number": 81,
-        "symbol": "Tl",
-        "atomic_mass": 204.38 * u.u,
-        "name": "thallium",
+        "atomic number": 81,
+        "atomic mass": 204.38 * u.u,
+        "element name": "thallium",
         "period": 6,
         "group": 13,
         "block": "p",
@@ -1142,10 +823,9 @@
     },
 
     "Pb": {
-        "atomic_number": 82,
-        "symbol": "Pb",
-        "atomic_mass": 207.2 * u.u,
-        "name": "lead",
+        "atomic number": 82,
+        "atomic mass": 207.2 * u.u,
+        "element name": "lead",
         "period": 6,
         "group": 14,
         "block": "p",
@@ -1153,10 +833,9 @@
     },
 
     "Bi": {
-        "atomic_number": 83,
-        "symbol": "Bi",
-        "atomic_mass": 208.98040 * u.u,
-        "name": "bismuth",
+        "atomic number": 83,
+        "atomic mass": 208.98040 * u.u,
+        "element name": "bismuth",
         "period": 6,
         "group": 15,
         "block": "p",
@@ -1164,9 +843,8 @@
     },
 
     "Po": {
-        "atomic_number": 84,
-        "symbol": "Po",
-        "name": "polonium",
+        "atomic number": 84,
+        "element name": "polonium",
         "period": 6,
         "group": 16,
         "block": "p",
@@ -1174,9 +852,8 @@
     },
 
     "At": {
-        "atomic_number": 85,
-        "symbol": "At",
-        "name": "astatine",
+        "atomic number": 85,
+        "element name": "astatine",
         "period": 6,
         "group": 17,
         "block": "p",
@@ -1184,9 +861,8 @@
     },
 
     "Rn": {
-        "atomic_number": 86,
-        "symbol": "Rn",
-        "name": "radon",
+        "atomic number": 86,
+        "element name": "radon",
         "period": 6,
         "group": 18,
         "block": "p",
@@ -1194,9 +870,8 @@
     },
 
     "Fr": {
-        "atomic_number": 87,
-        "symbol": "Fr",
-        "name": "francium",
+        "atomic number": 87,
+        "element name": "francium",
         "period": 7,
         "group": 1,
         "block": "s",
@@ -1204,9 +879,8 @@
     },
 
     "Ra": {
-        "atomic_number": 88,
-        "symbol": "Ra",
-        "name": "radium",
+        "atomic number": 88,
+        "element name": "radium",
         "period": 7,
         "group": 2,
         "block": "s",
@@ -1214,9 +888,8 @@
     },
 
     "Ac": {
-        "atomic_number": 89,
-        "symbol": "Ac",
-        "name": "actinium",
+        "atomic number": 89,
+        "element name": "actinium",
         "period": 7,
         "group": 3,
         "block": "d",
@@ -1224,10 +897,9 @@
     },
 
     "Th": {
-        "atomic_number": 90,
-        "symbol": "Th",
-        "atomic_mass": 232.0377 * u.u,
-        "name": "thorium",
+        "atomic number": 90,
+        "atomic mass": 232.0377 * u.u,
+        "element name": "thorium",
         "period": 7,
         "group": 3,
         "block": "f",
@@ -1235,10 +907,9 @@
     },
 
     "Pa": {
-        "atomic_number": 91,
-        "symbol": "Pa",
-        "atomic_mass": 231.03588 * u.u,
-        "name": "protactinium",
+        "atomic number": 91,
+        "atomic mass": 231.03588 * u.u,
+        "element name": "protactinium",
         "period": 7,
         "group": 3,
         "block": "f",
@@ -1246,10 +917,9 @@
     },
 
     "U": {
-        "atomic_number": 92,
-        "symbol": "U",
-        "atomic_mass": 238.02891 * u.u,
-        "name": "uranium",
+        "atomic number": 92,
+        "atomic mass": 238.02891 * u.u,
+        "element name": "uranium",
         "period": 7,
         "group": 3,
         "block": "f",
@@ -1257,9 +927,8 @@
     },
 
     "Np": {
-        "atomic_number": 93,
-        "symbol": "Np",
-        "name": "neptunium",
+        "atomic number": 93,
+        "element name": "neptunium",
         "period": 7,
         "group": 3,
         "block": "f",
@@ -1267,9 +936,8 @@
     },
 
     "Pu": {
-        "atomic_number": 94,
-        "symbol": "Pu",
-        "name": "plutonium",
+        "atomic number": 94,
+        "element name": "plutonium",
         "period": 7,
         "group": 3,
         "block": "f",
@@ -1277,9 +945,8 @@
     },
 
     "Am": {
-        "atomic_number": 95,
-        "symbol": "Am",
-        "name": "americium",
+        "atomic number": 95,
+        "element name": "americium",
         "period": 7,
         "group": 3,
         "block": "f",
@@ -1287,9 +954,8 @@
     },
 
     "Cm": {
-        "atomic_number": 96,
-        "symbol": "Cm",
-        "name": "curium",
+        "atomic number": 96,
+        "element name": "curium",
         "period": 7,
         "group": 3,
         "block": "f",
@@ -1297,9 +963,8 @@
     },
 
     "Bk": {
-        "atomic_number": 97,
-        "symbol": "Bk",
-        "name": "berkelium",
+        "atomic number": 97,
+        "element name": "berkelium",
         "period": 7,
         "group": 3,
         "block": "f",
@@ -1307,9 +972,8 @@
     },
 
     "Cf": {
-        "atomic_number": 98,
-        "symbol": "Cf",
-        "name": "californium",
+        "atomic number": 98,
+        "element name": "californium",
         "period": 7,
         "group": 3,
         "block": "f",
@@ -1317,9 +981,8 @@
     },
 
     "Es": {
-        "atomic_number": 99,
-        "symbol": "Es",
-        "name": "einsteinium",
+        "atomic number": 99,
+        "element name": "einsteinium",
         "period": 7,
         "group": 3,
         "block": "f",
@@ -1327,9 +990,8 @@
     },
 
     "Fm": {
-        "atomic_number": 100,
-        "symbol": "Fm",
-        "name": "fermium",
+        "atomic number": 100,
+        "element name": "fermium",
         "period": 7,
         "group": 3,
         "block": "f",
@@ -1337,9 +999,8 @@
     },
 
     "Md": {
-        "atomic_number": 101,
-        "symbol": "Md",
-        "name": "mendelevium",
+        "atomic number": 101,
+        "element name": "mendelevium",
         "period": 7,
         "group": 3,
         "block": "f",
@@ -1347,9 +1008,8 @@
     },
 
     "No": {
-        "atomic_number": 102,
-        "symbol": "No",
-        "name": "nobelium",
+        "atomic number": 102,
+        "element name": "nobelium",
         "period": 7,
         "group": 3,
         "block": "f",
@@ -1357,9 +1017,8 @@
     },
 
     "Lr": {
-        "atomic_number": 103,
-        "symbol": "Lr",
-        "name": "lawrencium",
+        "atomic number": 103,
+        "element name": "lawrencium",
         "period": 7,
         "group": 3,
         "block": "f",
@@ -1367,9 +1026,8 @@
     },
 
     "Rf": {
-        "atomic_number": 104,
-        "symbol": "Rf",
-        "name": "rutherfordium",
+        "atomic number": 104,
+        "element name": "rutherfordium",
         "period": 7,
         "group": 4,
         "block": "d",
@@ -1377,9 +1035,8 @@
     },
 
     "Db": {
-        "atomic_number": 105,
-        "symbol": "Db",
-        "name": "dubnium",
+        "atomic number": 105,
+        "element name": "dubnium",
         "period": 7,
         "group": 5,
         "block": "d",
@@ -1387,9 +1044,8 @@
     },
 
     "Sg": {
-        "atomic_number": 106,
-        "symbol": "Sg",
-        "name": "seaborgium",
+        "atomic number": 106,
+        "element name": "seaborgium",
         "period": 7,
         "group": 6,
         "block": "d",
@@ -1397,9 +1053,8 @@
     },
 
     "Bh": {
-        "atomic_number": 107,
-        "symbol": "Bh",
-        "name": "bohrium",
+        "atomic number": 107,
+        "element name": "bohrium",
         "period": 7,
         "group": 7,
         "block": "d",
@@ -1407,9 +1062,8 @@
     },
 
     "Hs": {
-        "atomic_number": 108,
-        "symbol": "Hs",
-        "name": "hassium",
+        "atomic number": 108,
+        "element name": "hassium",
         "period": 7,
         "group": 8,
         "block": "d",
@@ -1417,9 +1071,8 @@
     },
 
     "Mt": {
-        "atomic_number": 109,
-        "symbol": "Mt",
-        "name": "meitnerium",
+        "atomic number": 109,
+        "element name": "meitnerium",
         "period": 7,
         "group": 9,
         "block": "d",
@@ -1427,9 +1080,8 @@
     },
 
     "Ds": {
-        "atomic_number": 110,
-        "symbol": "Ds",
-        "name": "darmstadtium",
+        "atomic number": 110,
+        "element name": "darmstadtium",
         "period": 7,
         "group": 10,
         "block": "d",
@@ -1437,9 +1089,8 @@
     },
 
     "Rg": {
-        "atomic_number": 111,
-        "symbol": "Rg",
-        "name": "roentgenium",
+        "atomic number": 111,
+        "element name": "roentgenium",
         "period": 7,
         "group": 11,
         "block": "d",
@@ -1447,9 +1098,8 @@
     },
 
     "Cn": {
-        "atomic_number": 112,
-        "symbol": "Cn",
-        "name": "copernicium",
+        "atomic number": 112,
+        "element name": "copernicium",
         "period": 7,
         "group": 12,
         "block": "d",
@@ -1457,9 +1107,8 @@
     },
 
     "Nh": {
-        "atomic_number": 113,
-        "symbol": "Nh",
-        "name": "nihonium",
+        "atomic number": 113,
+        "element name": "nihonium",
         "period": 7,
         "group": 13,
         "block": "p",
@@ -1467,9 +1116,8 @@
     },
 
     "Fl": {
-        "atomic_number": 114,
-        "symbol": "Fl",
-        "name": "flerovium",
+        "atomic number": 114,
+        "element name": "flerovium",
         "period": 7,
         "group": 14,
         "block": "p",
@@ -1477,9 +1125,8 @@
     },
 
     "Mc": {
-        "atomic_number": 115,
-        "symbol": "Mc",
-        "name": "moscovium",
+        "atomic number": 115,
+        "element name": "moscovium",
         "period": 7,
         "group": 15,
         "block": "p",
@@ -1487,9 +1134,8 @@
     },
 
     "Lv": {
-        "atomic_number": 116,
-        "symbol": "Lv",
-        "name": "livermorium",
+        "atomic number": 116,
+        "element name": "livermorium",
         "period": 7,
         "group": 16,
         "block": "p",
@@ -1497,9 +1143,8 @@
     },
 
     "Ts": {
-        "atomic_number": 117,
-        "symbol": "Ts",
-        "name": "tennessine",
+        "atomic number": 117,
+        "element name": "tennessine",
         "period": 7,
         "group": 17,
         "block": "p",
@@ -1507,9 +1152,8 @@
     },
 
     "Og": {
-        "atomic_number": 118,
-        "symbol": "Og",
-        "name": "oganesson",
+        "atomic number": 118,
+        "element name": "oganesson",
         "period": 7,
         "group": 18,
         "block": "p",
@@ -1517,3 +1161,11 @@
     },
 
 }
+
+_atomic_numbers_to_symbols = {
+    elemdict['atomic number']: symb for (symb, elemdict) in _Elements.items()
+}
+
+_element_names_to_symbols = {
+    elemdict['element name']: symb for (symb, elemdict) in _Elements.items()
+}
diff --git a/plasmapy/atomic/parsing.py b/plasmapy/atomic/parsing.py
index a4506cf3..d877fa18 100644
--- a/plasmapy/atomic/parsing.py
+++ b/plasmapy/atomic/parsing.py
@@ -5,7 +5,7 @@
 import warnings
 from typing import (Union, Dict)
 
-from .elements import (_atomic_symbols, _atomic_symbols_dict, _Elements)
+from .elements import (_atomic_numbers_to_symbols, _element_names_to_symbols, _Elements)
 from .isotopes import _Isotopes
 from .special_particles import _Particles, ParticleZoo
 
@@ -75,8 +75,7 @@ def _create_alias_dicts(Particles: dict) -> (Dict[str, str], Dict[str, str]):
     return case_sensitive_aliases, case_insensitive_aliases
 
 
-_case_sensitive_aliases, _case_insensitive_aliases = \
-    _create_alias_dicts(_Particles)
+_case_sensitive_aliases, _case_insensitive_aliases = _create_alias_dicts(_Particles)
 
 
 def _dealias_particle_aliases(alias: Union[str, int]) -> str:
@@ -90,7 +89,7 @@ def _dealias_particle_aliases(alias: Union[str, int]) -> str:
     if not isinstance(alias, str):
         symbol = alias
     elif (alias in _case_sensitive_aliases.values() or
-            alias in _case_insensitive_aliases.values()):
+          alias in _case_insensitive_aliases.values()):
         symbol = alias
     elif alias in _case_sensitive_aliases.keys():
         symbol = _case_sensitive_aliases[alias]
@@ -119,10 +118,7 @@ def _invalid_particle_errmsg(argument, mass_numb=None, Z=None):
     return errmsg
 
 
-def _parse_and_check_atomic_input(
-        argument: Union[str, int],
-        mass_numb: int = None,
-        Z: int = None):
+def _parse_and_check_atomic_input(argument: Union[str, int], mass_numb: int = None, Z: int = None):
     """
     Parse information about a particle into a dictionary of standard
     symbols, and check the validity of the particle.
@@ -176,12 +172,10 @@ def _atomic_number_to_symbol(atomic_numb: int):
         not represent a known element.
         """
 
-        if atomic_numb in _atomic_symbols.keys():
-            element = _atomic_symbols[atomic_numb]
-            return element
+        if atomic_numb in _atomic_numbers_to_symbols.keys():
+            return _atomic_numbers_to_symbols[atomic_numb]
         else:
-            raise InvalidParticleError(
-                f"{atomic_numb} is not a valid atomic number.")
+            raise InvalidParticleError(f"{atomic_numb} is not a valid atomic number.")
 
     def _extract_charge(arg: str):
         """
@@ -193,8 +187,7 @@ def _extract_charge(arg: str):
         is inputted incorrectly.
         """
 
-        invalid_charge_errmsg = (
-            f"Invalid charge information in the particle string '{arg}'.")
+        invalid_charge_errmsg = (f"Invalid charge information in the particle string '{arg}'.")
 
         if arg.count(' ') == 1:  # Cases like 'H 1-' and 'Fe-56 1+'
             isotope_info, charge_info = arg.split(' ')
@@ -274,9 +267,9 @@ def _get_element(element_info: str) -> str:
         name, and returns a `str` representing the atomic symbol.
         """
 
-        if element_info.lower() in _atomic_symbols_dict.keys():
-            element = _atomic_symbols_dict[element_info.lower()]
-        elif element_info in _atomic_symbols.values():
+        if element_info.lower() in _element_names_to_symbols.keys():
+            element = _element_names_to_symbols[element_info.lower()]
+        elif element_info in _atomic_numbers_to_symbols.values():
             element = element_info
         else:
             raise InvalidParticleError(
@@ -342,8 +335,7 @@ def _reconstruct_ion_symbol(
         return ion
 
     if not isinstance(argument, (str, int)):  # coveralls: ignore
-        raise TypeError(f"The argument {argument} is not an integer or "
-                        "string.")
+        raise TypeError(f"The argument {argument} is not an integer or string.")
 
     arg = _dealias_particle_aliases(argument)
 
@@ -395,11 +387,10 @@ def _reconstruct_ion_symbol(
         Z = Z_from_arg
 
     if isinstance(Z, int):
-        if Z > _Elements[element]['atomic_number']:
+        if Z > _Elements[element]['atomic number']:
             raise InvalidParticleError(
                 f"The integer charge Z = {Z} cannot exceed the atomic number "
-                f"of {element}, which is "
-                f"{_Elements[element]['atomic_number']}.")
+                f"of {element}, which is {_Elements[element]['atomic number']}.")
         elif Z <= -3:
             warnings.warn(f"Particle '{argument}' has an integer charge "
                           f"of Z = {Z}, which is unlikely to occur in "
@@ -433,8 +424,7 @@ def _call_string(arg: Union[str, int], kwargs: Dict = {}) -> str:
     particle from the input.
     """
     if kwargs != {}:
-        keyword_string = ", " \
-            + str(kwargs).strip(r"}{'").replace("'", "").replace(":", " =")
+        keyword_string = ", " + str(kwargs).strip(r"}{'").replace("'", "").replace(":", " =")
     else:
         keyword_string = ""
     return f"Particle({repr(arg)}{keyword_string})"
diff --git a/plasmapy/atomic/particle_class.py b/plasmapy/atomic/particle_class.py
index 5b3bab61..48a111fa 100644
--- a/plasmapy/atomic/particle_class.py
+++ b/plasmapy/atomic/particle_class.py
@@ -14,6 +14,7 @@
     InvalidParticleError,
     InvalidElementError,
     InvalidIsotopeError,
+    InvalidIonError,
     ChargeError,
     MissingAtomicDataError,
     MissingAtomicDataWarning,
@@ -25,14 +26,11 @@
     _invalid_particle_errmsg,
 )
 
-from .elements import _Elements
+from .elements import _Elements, _PeriodicTable
 from .isotopes import _Isotopes
 
 from .special_particles import (_Particles, ParticleZoo, _special_ion_masses)
 
-_PeriodicTable = collections.namedtuple(
-    "periodic_table", ['group', 'category', 'block', 'period'])
-
 _classification_categories = {
     'lepton',
     'antilepton',
@@ -76,8 +74,26 @@
     'neutron',
 }
 
-_valid_categories = _periodic_table_categories | _classification_categories \
-    | _atomic_property_categories | _specific_particle_categories
+_valid_categories = (
+    _periodic_table_categories
+    | _classification_categories
+    | _atomic_property_categories
+    | _specific_particle_categories
+)
+
+
+def _category_errmsg(particle, category: str) -> str:
+    """
+    Return an error message when an attribute raises an
+    `~plasmapy.utils.InvalidElementError`,
+    `~plasmapy.utils.InvalidIonError`, or
+    `~plasmapy.utils.InvalidIsotopeError`.
+    """
+    article = 'an' if category[0] in 'aeiouAEIOU' else 'a'
+    errmsg = (
+        f"The particle {particle} is not {article} {category}, "
+        f"so this attribute is not available.")
+    return errmsg
 
 
 class Particle:
@@ -98,6 +114,10 @@ class Particle:
 
     Raises
     ------
+    `TypeError`
+        For when any of the arguments or keywords is not of the required
+        type.
+
     `~plasmapy.utils.InvalidParticleError`
         Raised when the particle input does not correspond to a valid
         particle or is contradictory.
@@ -113,30 +133,56 @@ class Particle:
         an isotope (or an ion of an isotope).
 
     `~plasmapy.utils.ChargeError`
-        For when either the charge or integer_charge attributes is being
-        accessed but the charge information for the particle is not
-        available.
+        For when either the `~plasmapy.atomic.Particle.charge` or
+        `~plasmapy.atomic.Particle.integer_charge` attributes is
+        being accessed but the charge information for the particle is
+        not available.
 
-    `TypeError`
-        For when any of the arguments or keywords is not of the required
-        type.
+    `~plasmapy.utils.AtomicError`
+        Raised for attempts at converting a Particle object to a `bool`.
 
     Examples
     --------
+    Particles may be defined using a wide variety of aliases:
+
     >>> proton = Particle('p+')
     >>> electron = Particle('e-')
     >>> neutron = Particle('neutron')
     >>> deuteron = Particle('D', Z=1)
     >>> alpha = Particle('He', mass_numb=4, Z=2)
     >>> positron = Particle('positron')
+    >>> hydrogen = Particle(1)  # atomic number
+
+    The `particle` attribute returns the particle's symbol in
+    the standard form.
+
+    >>> positron.particle
+    'e+'
+
+    The `element`, `isotope`, and `ion` attributes return the symbols
+    for each of these different types of particles.
+
+
     >>> proton.element
     'H'
     >>> alpha.isotope
     'He-4'
     >>> deuteron.ion
     'D 1+'
-    >>> positron.particle
-    'e+'
+    >>> positron.element is None
+    True
+
+    Because these attributes return `None` if the particle does not
+    belong to that type of particle, these attributes can be used to
+    test whether or not a particle is an element, isotope, or ion.
+
+    >>> True if Particle('e-').element else False
+    False
+    >>> True if Particle('alpha').ion else False
+    True
+
+    Many of the attributes return physical properties of a particle.
+
     >>> electron.integer_charge
     -1
     >>> proton.spin
@@ -153,32 +199,14 @@ class Particle:
     <Quantity 881.5 s>
     >>> Particle('C-14').half_life.to(u.year)
     <Quantity 5730. yr>
+    >>> deuteron.electron_number
+    0
+    >>> alpha.neutron_number
+    2
 
-    The `periodic_table` attribute provides category, period, block, and
-    group information if the particle corresponds to an element.
-
-    >>> sulfur = Particle('S')
-    >>> sulfur.periodic_table.category
-    'nonmetal'
-    >>> sulfur.periodic_table.block
-    'p'
-    >>> sulfur.periodic_table.period
-    3
-    >>> sulfur.periodic_table.group
-    16
-
-    The `is_category` attribute may be used to determine whether or not
-    a certain particle is or is not a member of a certain category.
-
-    >>> electron.is_category('lepton')
-    True
-    >>> proton.is_category('baryon', exclude='charged')
-    False
-    >>> neutron.is_category({'matter', 'baryon'}, exclude={'charged'})
-    True
-    >>> positron.is_category('antilepton', exclude='baryon')
-    True
-
+    The `~plasmapy.atomic.particle_class.Particle.categories` attribute
+    and `~plasmapy.atomic.particle_class.Particle.is_category` method
+    may be used to find and test particle membership in categories.
     Valid categories include `'lepton'`, `'antilepton'`, `'fermion'`,
     `'boson'`, `'baryon'`, `'neutrino'`, `'antineutrino'`, `'element'`,
     `'isotope'`, `'ion'`, `'matter'`, `'antimatter'`, `'nonmetal'`,
@@ -190,11 +218,11 @@ class Particle:
 
     """
 
-    def __init__(self,
-                 argument: Union[str, int],
-                 mass_numb: int = None,
-                 Z: int = None):
-        """Initialize a Particle object and set private attributes."""
+    def __init__(self, argument: Union[str, int], mass_numb: int = None, Z: int = None):
+        """
+        Initialize a `~plasmapy.atomic.Particle` object and set private
+        attributes.
+        """
 
         if not isinstance(argument, (int, str)):
             raise TypeError(
@@ -214,6 +242,7 @@ def __init__(self,
         # 'lepton' for use with the is_category method later on.
 
         self._categories = set()
+        categories = self._categories
 
         # If the argument corresponds to one of the case-sensitive or
         # case-insensitive aliases for particles, return the standard
@@ -221,224 +250,233 @@ def __init__(self,
 
         particle = _dealias_particle_aliases(argument)
 
-        attributes['particle'] = particle
-
         if particle in _Particles.keys():  # special particles
-            special_particle_keys = [
-                'name',
-                'spin',
-                'class',
-                'lepton number',
-                'baryon number',
-                'integer charge',
-                'half-life',
-                'mass',
-            ]
-
-            for key in special_particle_keys:
-                attributes[key] = _Particles[particle].get(key, None)
-
-            particle_taxonomy_dict = ParticleZoo._taxonomy_dict
-            categories = particle_taxonomy_dict.keys()
-
-            for category in categories:
-                if particle in particle_taxonomy_dict[category]:
-                    self._categories.add(category)
+
+            attributes['particle'] = particle
+
+            for attribute in _Particles[particle].keys():
+                attributes[attribute] = _Particles[particle][attribute]
+
+            particle_taxonomy = ParticleZoo._taxonomy_dict
+            all_categories = particle_taxonomy.keys()
+
+            for category in all_categories:
+                if particle in particle_taxonomy[category]:
+                    categories.add(category)
 
             if attributes['name'] in _specific_particle_categories:
-                self._categories.add(attributes['name'])
+                categories.add(attributes['name'])
 
             if particle == 'p+':
-
-                # Protons are a special case amongst special cases, since they
-                # are both a special particle and correspond to an element and
-                # an isotope.  Protons are not as weird as electrons, though.
-                # Electrons are weird.
-
-                proton_keys_and_vals = [
-                    ('element', 'H'),
-                    ('atomic number', 1),
-                    ('mass number', 1),
-                    ('element name', 'hydrogen'),
-                    ('isotope', 'H-1'),
-                    ('ion', 'p+'),
-                    ('mass', const.m_p),
-                    ('integer charge', 1),
-                ]
-
-                self._periodic_table = _PeriodicTable(
-                    group=_Elements['H']['group'],
-                    period=_Elements['H']['period'],
-                    block=_Elements['H']['block'],
-                    category=_Elements['H']['category'],
-                )
-
-                for key, val in proton_keys_and_vals:
-                    attributes[key] = val
-
-                self._categories.update({'element', 'isotope', 'ion'})
+                categories.update({'element', 'isotope', 'ion'})
 
             if mass_numb is not None or Z is not None:
                 if particle == 'p+' and (mass_numb == 1 or Z == 1):
-                    warnings.warn(
-                        "Redundant mass number or charge information.",
-                        AtomicWarning)
+                    warnings.warn("Redundant mass number or charge information.", AtomicWarning)
                 else:
                     raise InvalidParticleError(
                         "The keywords 'mass_numb' and 'Z' cannot be used when "
                         "creating Particle objects for special particles. To "
-                        f"create a Particle object for "
-                        f"{attributes['name']}s, "
+                        f"create a Particle object for {attributes['name']}s, "
                         f"use:  Particle({repr(attributes['particle'])})")
 
         else:  # elements, isotopes, and ions (besides protons)
             try:
-
-                atomic_nomenclature_dict = _parse_and_check_atomic_input(
-                    argument, mass_numb=mass_numb, Z=Z)
-
-                element_keys = [
-                    'particle',
-                    'element',
-                    'isotope',
-                    'ion',
-                    'mass number',
-                    'integer charge',
-                ]
-
-                for key in element_keys:
-                    attributes[key] = \
-                        atomic_nomenclature_dict.get(key, None)
-
+                nomenclature = _parse_and_check_atomic_input(argument, mass_numb=mass_numb, Z=Z)
             except Exception as exc:
-                errmsg = _invalid_particle_errmsg(
-                    argument, mass_numb=mass_numb, Z=Z)
+                errmsg = _invalid_particle_errmsg(argument, mass_numb=mass_numb, Z=Z)
                 raise InvalidParticleError(errmsg) from exc
 
+            for key in nomenclature.keys():
+                attributes[key] = nomenclature[key]
+
             element = attributes['element']
             isotope = attributes['isotope']
             ion = attributes['ion']
 
             if element:
-                self._categories.add('element')
+                categories.add('element')
             if isotope:
-                self._categories.add('isotope')
+                categories.add('isotope')
             if ion:
-                self._categories.add('ion')
+                categories.add('ion')
 
             # Element properties
 
-            attributes['atomic number'] = \
-                _Elements[element]['atomic_number']
-            attributes['element name'] = _Elements[element]['name']
+            Element = _Elements[element]
 
-            attributes['element name'] = _Elements[element]['name']
-            attributes['baryon number'] = attributes['mass number']
+            attributes['atomic number'] = Element['atomic number']
+            attributes['element name'] = Element['element name']
 
-            # For the moment, set the lepton number to zero for elements,
-            # isotopes, and ions.  The lepton number will probably come up
-            # primarily during nuclear reactions.
+            # Set the lepton number to zero for elements, isotopes, and
+            # ions.  The lepton number will probably come up primarily
+            # during nuclear reactions.
 
             attributes['lepton number'] = 0
 
             if isotope:
-                if _Isotopes[isotope]['stable']:
+
+                Isotope = _Isotopes[isotope]
+
+                attributes['baryon number'] = Isotope['mass number']
+                attributes['isotope mass'] = Isotope.get('mass', None)
+                attributes['isotopic abundance'] = Isotope.get('abundance', 0.0)
+
+                if Isotope['stable']:
                     attributes['half-life'] = np.inf * u.s
                 else:
-                    attributes['half-life'] = \
-                        _Isotopes[isotope].get('half-life', None)
-
-            if ion == 'He-4 2+':
-                attributes['spin'] = 0
-                self._categories.add('boson')
+                    attributes['half-life'] = Isotope.get('half-life', None)
 
             if element and not isotope:
-                attributes['standard atomic weight'] = \
-                    _Elements[element].get('atomic_mass', None)
-
-            if isotope:
-                attributes['isotope mass'] = \
-                    _Isotopes[isotope].get('mass', None)
-                attributes['isotopic abundance'] = \
-                    _Isotopes[isotope].get('abundance', 0.0)
+                attributes['standard atomic weight'] = Element.get('atomic mass', None)
 
             if ion in _special_ion_masses.keys():
                 attributes['mass'] = _special_ion_masses[ion]
 
-            self._periodic_table = _PeriodicTable(
-                group=_Elements[element]['group'],
-                period=_Elements[element]['period'],
-                block=_Elements[element]['block'],
-                category=_Elements[element]['category'],
+            attributes['periodic table'] = _PeriodicTable(
+                group=Element['group'],
+                period=Element['period'],
+                block=Element['block'],
+                category=Element['category'],
             )
 
-            self._categories.add(self._periodic_table.category)
+            categories.add(Element['category'])
 
         if attributes['integer charge'] == 1:
             attributes['charge'] = const.e.si
         elif attributes['integer charge'] is not None:
-            attributes['charge'] = \
-                attributes['integer charge'] * const.e.si
+            attributes['charge'] = attributes['integer charge'] * const.e.si
 
         if attributes['integer charge']:
-            self._categories.add('charged')
+            categories.add('charged')
         elif attributes['integer charge'] == 0:
-            self._categories.add('uncharged')
+            categories.add('uncharged')
 
         if attributes['half-life'] is not None:
             if attributes['half-life'] == np.inf * u.s:
-                self._categories.add('stable')
+                categories.add('stable')
             else:
-                self._categories.add('unstable')
+                categories.add('unstable')
 
-        self._element_errmsg = (
-            f"The particle '{self.particle}' is not an element, so "
-            f"this attribute is not available.")
-
-        self._isotope_errmsg = (
-            f"The particle '{self.particle}' does not have an "
-            f"isotope specified, so this attribute is not available.")
+    def __repr__(self) -> str:
+        """Return a call string that would recreate this object.
 
-        self._ion_errmsg = (
-            f"The particle '{self.particle}' is not an ion, so this"
-            f"attribute is not available.")
+        Examples
+        --------
+        >>> lead = Particle('lead')
+        >>> repr(lead)
+        'Particle("Pb")'
 
-    def __repr__(self) -> str:
-        """Return a string of the call that would recreate this object."""
+        """
         return f'Particle("{self.particle}")'
 
     def __str__(self) -> str:
-        """Return a string of the particle symbol."""
-        return f"{self.particle}"
+        """Return the particle's symbol."""
+        return self.particle
 
     def __eq__(self, other) -> bool:
         """
-        Return True when comparing two Particle objects that correspond
-        to the same particle, and False when the two objects differ.
+        Determine if two objects correspond to the same particle.
+
+        This method will return `True` if `other` is an identical
+        `~plasmapy.atomic.Particle` instance or a `str` representing the
+        same particle, and return `False` if `other` is a different
+        `~plasmapy.atomic.Particle` or a `str` representing a different
+        particle.
+
+        If `other` is not a `str` or `~plasmapy.atomic.Particle`
+        instance, then this method will raise a `TypeError`.  If
+        `other.particle` equals `self.particle` but the attributes
+        differ, then this method will raise a
+        `~plasmapy.utils.AtomicError`.
+
+        Examples
+        --------
+        >>> electron = Particle('e-')
+        >>> positron = Particle('e+')
+        >>> electron == positron
+        False
+        >>> electron == 'e-'
+        True
+
         """
+        if isinstance(other, str):
+            try:
+                other_particle = Particle(other)
+                return self.particle == other_particle.particle
+            except InvalidParticleError as exc:
+                raise InvalidParticleError(
+                    f"{other} is not a particle and cannot be "
+                    f"compared to {self}.")
+
+        if not isinstance(other, self.__class__):
+            raise TypeError(
+                f"The equality of a Particle object with a {type(other)} is undefined.")
 
-        if not isinstance(other, Particle):
-            return False
+        same_particle = self.particle == other.particle
 
-        try:
-            if self.particle == other.particle:
-                return True
-            else:
-                return False
-        except Exception:  # coveralls: ignore
-            return False
+        # The following two loops are a hack to enable comparisons
+        # between defaultdicts.  By accessing all of the defined keys in
+        # each of the defaultdicts, this makes sure that
+        # self._attributes and other._attributes have the same keys.
+
+        # TODO: create function in utils to account for equality between
+        # defaultdicts, and implement it here
+
+        for attribute in self._attributes.keys():
+            other._attributes[attribute]
+
+        for attribute in other._attributes.keys():
+            self._attributes[attribute]
+
+        same_attributes = self._attributes == other._attributes
+
+        if same_particle and not same_attributes:  # coveralls: ignore
+            raise AtomicError(
+                f"{self} and {other} should be the same Particle, but "
+                f"have differing attributes.\n\n"
+                f"The attributes of {self} are:\n\n{self._attributes}\n\n"
+                f"The attributes of {other} are:\n\n{other._attributes}\n")
+
+        return same_particle
 
     def __ne__(self, other) -> bool:
         """
-        Return `True` when the two objects differ, and False when
-        comparing two Particle objects that correspond to the same
+        Test whether or not two objects are different particles.
+
+        This method will return `False` if `other` is an identical
+        `~plasmapy.atomic.Particle` instance or a `str` representing the
+        same particle, and return `True` if `other` is a different
+        `~plasmapy.atomic.Particle` or a `str` representing a different
         particle.
+
+        If `other` is not a `str` or `~plasmapy.atomic.Particle`
+        instance, then this method will raise a `TypeError`.  If
+        `other.particle` equals `self.particle` but the attributes
+        differ, then this method will raise a
+        `~plasmapy.utils.AtomicError`.
+
         """
         return not self.__eq__(other)
 
+    def __bool__(self):
+        """
+        Raise an `~plasmapy.utils.AtomicError` because Particle objects
+        do not have a truth value.
+        """
+        raise AtomicError("The truthiness of a Particle object is not defined.")
+
     @property
     def particle(self) -> str:
-        """Return the particle symbol."""
+        """Return the particle's symbol.
+
+        Examples
+        --------
+        >>> electron = Particle('electron')
+        >>> electron.particle
+        'e-'
+
+        """
         return self._attributes['particle']
 
     @property
@@ -446,6 +484,13 @@ def element(self) -> Optional[str]:
         """
         Return the atomic symbol if the particle corresponds to an
         element, and `None` otherwise.
+
+        Examples
+        --------
+        >>> alpha = Particle('alpha')
+        >>> alpha.element
+        'He'
+
         """
         return self._attributes['element']
 
@@ -454,6 +499,13 @@ def isotope(self) -> Optional[str]:
         """
         Return the isotope symbol if the particle corresponds to an
         isotope, and `None` otherwise.
+
+        Examples
+        --------
+        >>> alpha = Particle('alpha')
+        >>> alpha.isotope
+        'He-4'
+
         """
         return self._attributes['isotope']
 
@@ -462,6 +514,13 @@ def ion(self) -> Optional[str]:
         """
         Return the ion symbol if the particle corresponds to an ion,
         and `None` otherwise.
+
+        Examples
+        --------
+        >>> deuteron = Particle('deuteron')
+        >>> deuteron.ion
+        'D 1+'
+
         """
         return self._attributes['ion']
 
@@ -469,67 +528,104 @@ def ion(self) -> Optional[str]:
     def element_name(self) -> str:
         """
         Return the name of the element corresponding to this
-        particle, or raises an `~plasmapy.utils.InvalidElementError` if
+        particle, or raise an `~plasmapy.utils.InvalidElementError` if
         the particle does not correspond to an element.
+
+        Examples
+        --------
+        >>> tritium = Particle('T')
+        >>> tritium.element_name
+        'hydrogen'
+
         """
         if not self.element:
-            raise InvalidElementError(self._element_errmsg)
+            raise InvalidElementError(_category_errmsg(self, 'element'))
         return self._attributes['element name']
 
     @property
     def integer_charge(self) -> int:
         """
-        Return the integer charge of the particle, or raises a
-        `~plasmapy.utils.ChargeError` if the charge has not been
-        specified.
+        Return the particle's integer charge.
+
+        This attribute will raise a `~plasmapy.utils.ChargeError` if the
+        charge has not been specified.
+
+        Examples
+        --------
+        >>> muon = Particle('mu-')
+        >>> muon.integer_charge
+        -1
+
         """
         if self._attributes['integer charge'] is None:
-            raise ChargeError(
-                f"The charge of particle {self.particle} has not been "
-                f"specified.")
+            raise ChargeError(f"The charge of particle {self} has not been specified.")
         return self._attributes['integer charge']
 
     @property
     def charge(self) -> u.Quantity:
         """
-        Return the electric charge as a `~astropy.units.Quantity`
-        in units of coulombs, or raises a `~plasmapy.utils.ChargeError`
-        if the charge has not been specified.
+        Return the particle's electron charge in coulombs.
+
+        This attribute will raise a `~plasmapy.utils.ChargeError` if the
+        charge has not been specified.
+
+        Examples
+        --------
+        >>> electron = Particle('e-')
+        >>> electron.charge
+        <Quantity -1.60217662e-19 C>
+
         """
         if self._attributes['charge'] is None:
-            raise ChargeError(
-                f"The charge of particle {self.particle} has not been "
-                f"specified.")
+            raise ChargeError(f"The charge of particle {self} has not been specified.")
         if self._attributes['integer charge'] == 1:
-            return const.e
+            return const.e.si
 
         return self._attributes['charge']
 
     @property
     def standard_atomic_weight(self) -> u.Quantity:
         """
-        Return the standard atomic weight of an element if
-        available.  Raises a `~plasmapy.utils.MissingAtomicDataError` if
-        the particle is an element for which the standard atomic weight
-        is unavailable.  Raises an `~plasmapy.utils.InvalidElementError`
-        if the particle is not an element.
+        Return an element's standard atomic weight in kg.
+
+        If the particle is isotope or ion or not an element, this
+        attribute will raise an `~plasmapy.utils.InvalidElementError`.
+
+        If the element does not have a defined stsandard atomic weight,
+        this attribute will raise a
+        `~plasmapy.utils.MissingAtomicDataError`.
+
+        Examples
+        --------
+        >>> oxygen = Particle('O')
+        >>> oxygen.standard_atomic_weight
+        <Quantity 2.65669641e-26 kg>
+
         """
         if self.isotope or self.ion or not self.element:
-            raise InvalidElementError(self._element_errmsg)
-        if self._attributes['standard atomic weight'] is None:
+            raise InvalidElementError(_category_errmsg(self, 'element'))
+        if self._attributes['standard atomic weight'] is None:  # coveralls: ignore
             raise MissingAtomicDataError(
-                f"The standard atomic weight of {self.element} is "
-                f"unavailable.")
-        return self._attributes['standard atomic weight']
+                f"The standard atomic weight of {self} is unavailable.")
+        return self._attributes['standard atomic weight'].to(u.kg)
 
     @property
     def nuclide_mass(self) -> u.Quantity:
         """
-        Return the mass of the nucleus of an isotope.  This
-        attribute raises an `~plasmapy.utils.InvalidIsotopeError` if the
-        particle is not an isotope or neutron, or a
+        Return the mass of the bare nucleus of an isotope or a neutron.
+
+        This attribute will raise a
+        `~plasmapy.utils.InvalidIsotopeError` if the particle is not an
+        isotope or neutron, or a
         `~plasmapy.utils.MissingAtomicDataError` if the isotope mass is
         not available.
+
+        Examples
+        --------
+        >>> deuterium = Particle('D')
+        >>> deuterium.nuclide_mass
+        <Quantity 3.34358372e-27 kg>
+
         """
 
         if self.particle in ['H-1', 'p+']:
@@ -542,42 +638,56 @@ def nuclide_mass(self) -> u.Quantity:
             return _special_ion_masses['T 1+']
 
         if not self.isotope:
-            raise InvalidIsotopeError(self._isotope_errmsg)
+            raise InvalidIsotopeError(_category_errmsg(self, 'isotope'))
 
         base_mass = self._attributes['isotope mass']
 
-        if base_mass is None:
-            raise MissingAtomicDataError(
-                f"The mass of a {self.isotope} nuclide is not available.")
+        if base_mass is None:  # coveralls: ignore
+            raise MissingAtomicDataError(f"The mass of a {self.isotope} nuclide is not available.")
 
-        _nuclide_mass = \
-            self._attributes['isotope mass'] - self.atomic_number * const.m_e
+        _nuclide_mass = self._attributes['isotope mass'] - self.atomic_number * const.m_e
 
         return _nuclide_mass.to(u.kg)
 
     @property
     def mass(self) -> u.Quantity:
         """
-        Return the mass of the element, isotope, ion, particle, or
-        antiparticle; or raises a
-        `~plasmapy.utils.MissingAtomicDataError` if the mass is
-        unavailable (e.g., if the particle is a neutrino).
-
-        For special particles, this attribute will return the standard
-        value of the mass of the particle.
+        Return the mass of the particle in kilograms.
 
         If the particle is an element and not an isotope or ion, then
-        this attribute will return the standard atomic weight if
-        available. If the particle is an isotope but not an ion, then
-        this attribute will return the isotopic mass. If this particle
-        is an ion, then this attribute will return the mass of the
-        element or isotope (as just described) minus the integer charge
-        times the electron mass.
+        this attribute will return the standard atomic weight, if
+        available.
+
+        If the particle is an isotope but not an ion, then this
+        attribute will return the isotopic mass, including bound
+        electrons.
+
+        If the particle is an ion, then this attribute will return the
+        mass of the element or isotope (as just described) minus the
+        product of the integer charge and the electron mass.
+
+        For special particles, this attribute will return the standard
+        value for the particle's mass.
+
+        If the mass is unavailable (e.g., for neutrinos or elements with
+        no standard atomic weight), then this attribute will raise a
+        `~plasmapy.utils.MissingAtomicDataError`.
+
+        Examples
+        --------
+        >>> Particle('He').mass
+        <Quantity 6.64647688e-27 kg>
+        >>> Particle('He+').mass
+        <Quantity 6.64556594e-27 kg>
+        >>> Particle('He-4 +1').mass
+        <Quantity 6.64556803e-27 kg>
+        >>> Particle('alpha').mass
+        <Quantity 6.64465709e-27 kg>
 
         """
 
         if self._attributes['mass'] is not None:
-            return self._attributes['mass']
+            return self._attributes['mass'].to(u.kg)
 
         if self.ion:
 
@@ -587,8 +697,7 @@ def mass(self) -> u.Quantity:
                 base_mass = self._attributes['standard atomic weight']
 
             if base_mass is None:
-                raise MissingAtomicDataError(
-                    f"The mass of ion '{self.ion}' is not available.")
+                raise MissingAtomicDataError(f"The mass of ion '{self.ion}' is not available.")
 
             mass = base_mass - self.integer_charge * const.m_e
 
@@ -602,87 +711,206 @@ def mass(self) -> u.Quantity:
                 mass = self._attributes['standard atomic weight']
 
             if mass is not None:
-                return mass
+                return mass.to(u.kg)
 
-        raise MissingAtomicDataError(
-            f"The mass of {self.particle} is not available.")
+        raise MissingAtomicDataError(f"The mass of {self} is not available.")
 
     @property
     def atomic_number(self) -> int:
         """
-        Return the atomic number of the element corresponding to
-        this particle, or raises an `~plasmapy.utils.InvalidElementError`
-        if the particle does not correspond to an element.
+        Return the number of protons in an element, isotope, or ion.
+
+        If the particle is not an element, then this attribute will
+        raise an `~plasmapy.utils.InvalidElementError`.
+
+        Examples
+        --------
+        >>> proton = Particle('p+')
+        >>> proton.atomic_number
+        1
+        >>> curium = Particle('Cm')
+        >>> curium.atomic_number
+        96
+
         """
         if not self.element:
-            raise InvalidElementError(self._element_errmsg)
+            raise InvalidElementError(_category_errmsg(self, 'element'))
         return self._attributes['atomic number']
 
     @property
     def mass_number(self) -> int:
         """
-        Return the mass number of the isotope corresponding to this
-        particle, or raises an `~plasmapy.utils.InvalidIsotopeError` if
-        the particle does not correspond to an isotope.
+        Return the number of nucleons in an isotope.
+
+        This attribute will return the number of protons plus the number
+        of neutrons in an isotope or nuclide.
+
+        If the particle is not an isotope, then this attribute will
+        raise an `~plasmapy.utils.InvalidIsotopeError`.
+
+        Examples
+        --------
+        >>> alpha = Particle('helium-4 2+')
+        >>> alpha.mass_number
+        4
+
         """
         if not self.isotope:
-            raise InvalidIsotopeError(self._isotope_errmsg)
+            raise InvalidIsotopeError(_category_errmsg(self, 'isotope'))
         return self._attributes['mass number']
 
     @property
     def neutron_number(self) -> int:
         """
-        Return the number of neutrons of the isotope corresponding
-        to this particle, or raises an `~plasmapy.utils.InvalidIsotopeError` if
-        the particle does not correspond to an isotope.
+        Return the number of neutrons in an isotope or nucleon.
+
+        This attribute will return the number of neutrons in an isotope,
+        or `1` for a neutron.
+
+        If this particle is not an isotope or neutron, then this
+        attribute will raise an `~plasmapy.utils.InvalidIsotopeError`.
+
+        Examples
+        --------
+        >>> alpha = Particle('He-4++')
+        >>> alpha.neutron_number
+        2
+        >>> Particle('n').neutron_number
+        1
+
+        """
+        if self.particle == 'n':
+            return 1
+        elif self.isotope:
+            return self.mass_number - self.atomic_number
+        else:  # coveralls: ignore
+            raise InvalidIsotopeError(_category_errmsg(self, 'isotope'))
+
+    @property
+    def electron_number(self) -> int:
+        """
+        Return the number of electrons in an ion.
+
+        This attribute will return the number of bound electrons in an
+        ion, or `1` for an electron.
+
+        If this particle is not an ion or electron, then this attribute
+        will raise an `~plasmapy.utils.InvalidIonError`.
+
+        Examples
+        --------
+        >>> Particle('Li 0+').electron_number
+        3
+        >>> Particle('e-').electron_number
+        1
+
         """
-        return self.mass_number - self.atomic_number
+        if self.particle == 'e-':
+            return 1
+        elif self.ion:
+            return self.atomic_number - self.integer_charge
+        else:  # coveralls: ignore
+            raise InvalidIonError(_category_errmsg(self, 'ion'))
 
     @property
     def isotopic_abundance(self) -> u.Quantity:
         """
-        Return the isotopic abundance of an isotope if available,
-        or raises a `~plasmapy.utils.MissingAtomicDataError`.
+        Return the isotopic abundance of an isotope.
+
+        If the isotopic abundance is not available, this attribute will
+        raise a `~plasmapy.utils.MissingAtomicDataError`.  If the
+        particle is not an isotope or is an ion of an isotope, then this
+        attribute will raise an `~plasmapy.utils.InvalidIsotopeError`.
+
+        Examples
+        --------
+        >>> D = Particle('deuterium')
+        >>> D.isotopic_abundance
+        0.000115
+
         """
-        if not self.isotope:
-            raise InvalidIsotopeError(self._isotope_errmsg)
-        # TODO: Raise exception when element doesn't occur naturally
-        return self._attributes.get('isotopic abundance', 0.0)
+        from .atomic import common_isotopes
+
+        if not self.isotope or self.ion:  # coveralls: ignore
+            raise InvalidIsotopeError(_category_errmsg(self.particle, 'isotope'))
+
+        abundance = self._attributes.get('isotopic abundance', 0.0)
+
+        if not common_isotopes(self.element):
+            warnings.warn(
+                f'No isotopes of {self.element} have an isotopic abundance. '
+                f'The isotopic abundance of {self.isotope} is being returned as 0.0',
+                AtomicWarning)
+
+        return abundance
 
     @property
     def baryon_number(self) -> int:
         """
-        Return the number of protons plus neutrons minus the number
-        of antiprotons and antineutrons in the particle, or raises an
-        `~plasmapy.utils.AtomicError` if the baryon number is
-        unavailable. The baryon number is equivalent to the mass number
-        for isotopes.
+        Return the number of baryons in a particle.
+
+        This attribute will return the number of protons and neutrons
+        minus the number of antiprotons and antineutrons. The baryon
+        number is equivalent to the mass number for isotopes.
+
+        If the baryon number is unavailable, then this attribute will
+        raise a `~plasmapy.utils.MissingAtomicDataError`.
+
+        Examples
+        --------
+        >>> alpha = Particle('alpha')
+        >>> alpha.baryon_number
+        4
+
         """
         if self._attributes['baryon number'] is None:  # coveralls: ignore
-            raise AtomicError(
-                f"The baryon number for '{self.particle}' is not "
-                f"available.")
+            raise MissingAtomicDataError(
+                f"The baryon number for '{self.particle}' is not available.")
         return self._attributes['baryon number']
 
     @property
     def lepton_number(self) -> int:
         """
-        Return 1 for leptons, -1 for antileptons, and 0 for
-        nuclides/isotopes; or raises an `~plasmapy.utils.AtomicError` if
-        the lepton number is not available.  This attribute does not
-        count the electrons in an atom or ion.
+        Return `1` for leptons, `-1` for antileptons, and `0` otherwise.
+
+        This attribute returns the number of leptons minus the number of
+        antileptons, excluding bound electrons in an atom or ion.
+
+        If the lepton number is unavailable, then this attribute will
+        raise a `~plasmapy.utils.MissingAtomicDataError`.
+
+        Examples
+        --------
+        >>> Particle('e-').lepton_number
+        1
+        >>> Particle('mu+').lepton_number
+        -1
+        >>> Particle('He-4 0+').lepton_number
+        0
+
         """
         if self._attributes['lepton number'] is None:  # coveralls: ignore
-            raise AtomicError(
+            raise MissingAtomicDataError(
                 f"The lepton number for {self.particle} is not available.")
         return self._attributes['lepton number']
 
     @property
     def binding_energy(self) -> u.Quantity:
         """
-        Return the nuclear binding energy, or raises an
+        Return the nuclear binding energy in joules.
+
+        This attribute will raise an
         `~plasmapy.utils.InvalidIsotopeError` if the particle is not a
         nucleon or isotope.
+
+        Examples
+        --------
+        >>> alpha = Particle('alpha')
+        >>> alpha.binding_energy
+        <Quantity 4.53346938e-12 J>
+        >>> Particle('T').binding_energy.to('MeV')
+        <Quantity 8.48179621 MeV>
+
         """
 
         if self._attributes['baryon number'] == 1:
@@ -690,8 +918,7 @@ def binding_energy(self) -> u.Quantity:
 
         if not self.isotope:
             raise InvalidIsotopeError(
-                f"The nuclear binding energy may only be calculated for "
-                f"nucleons and isotopes.")
+                f"The nuclear binding energy may only be calculated for nucleons and isotopes.")
 
         number_of_protons = self.atomic_number
         number_of_neutrons = self.mass_number - self.atomic_number
@@ -707,36 +934,53 @@ def binding_energy(self) -> u.Quantity:
         return nuclear_binding_energy.to(u.J)
 
     @property
-    def half_life(self) -> u.Quantity:
+    def half_life(self) -> Union[u.Quantity, str]:
         """
-        Return the half-life of the particle, or raises a
-        `~plasmapy.utils.MissingAtomicDataError` if the half-life is
-        unavailable.
+        Return the particle's half-life in seconds, or a `str`
+        with half-life information.
+
+        Particles that do not have sufficiently well-constrained
+        half-lives will return a `str` containing the information
+        that is available about the half-life and issue a
+        `~plasmapy.utils.MissingAtomicDataWarning`.
+
+        Examples
+        --------
+        >>> neutron = Particle('n')
+        >>> neutron.half_life
+        <Quantity 881.5 s>
+
         """
         if self.element and not self.isotope:
-            raise InvalidIsotopeError(self._isotope_errmsg)
+            raise InvalidIsotopeError(_category_errmsg(self.particle, 'isotope'))
 
         if isinstance(self._attributes['half-life'], str):
             warnings.warn(
                 f"The half-life for {self.particle} is not known precisely; "
-                "returning string with estimated value.",
-                MissingAtomicDataWarning)
+                "returning string with estimated value.", MissingAtomicDataWarning)
 
         if self._attributes['half-life'] is None:
-            raise MissingAtomicDataError(
-                f"The half-life of '{self.particle}' is not available.")
+            raise MissingAtomicDataError(f"The half-life of '{self.particle}' is not available.")
         return self._attributes['half-life']
 
     @property
     def spin(self) -> Union[int, float]:
         """
-        Return the spin of the particle, or raises a
-        `~plasmapy.utils.MissingAtomicDataError` if the spin is not
-        available.
+        Return the spin of the particle.
+
+        If the spin is unavailable, then a
+        `~plasmapy.utils.MissingAtomicDataError` will be raised.
+
+        Examples
+        --------
+        >>> positron = Particle('e+')
+        >>> positron.spin
+        0.5
+
         """
         if self._attributes['spin'] is None:
-            raise MissingAtomicDataError(
-                f"The spin of particle '{self.particle}' is unavailable.")
+            raise MissingAtomicDataError(f"The spin of particle '{self.particle}' is unavailable.")
+
         return self._attributes['spin']
 
     @property
@@ -746,56 +990,39 @@ def periodic_table(self):
         group, and block information about an element.
 
         If the particle is not an element, isotope, or ion, then this
-        method will raise an `~plasmapy.utils.InvalidElementError`.
-        """
-        if self.element:
-            return self._periodic_table
-        else:
-            raise InvalidElementError(self._element_errmsg)
-
-    def reduced_mass(self, other, Z=None, mass_numb=None) -> u.Quantity:
-        """
-        Find the reduced mass between two particles, or will raise
-        a `~plasmapy.utils.MissingAtomicDataError` if either particle's
-        mass is unavailable or an `~plasmapy.utils.AtomicError` for any
-        other errors.  The other particle may be represented by another
-        Particle object, a `~astropy.units.Quantity` with units of mass,
-        or a string of the other particle's symbol (in conjunction with
-        keywords `Z` and `mass_numb`).
+        attribute will raise an `~plasmapy.utils.InvalidElementError`.
+
+        Examples
+        --------
+        >>> gold = Particle('Au')
+        >>> gold.periodic_table.category
+        'transition metal'
+        >>> gold.periodic_table.period
+        6
+        >>> gold.periodic_table.group
+        11
+        >>> gold.periodic_table.block
+        'd'
 
         """
-
-        try:
-            mass_this = self.mass.to(u.kg)
-        except MissingAtomicDataError:
-            raise MissingAtomicDataError(
-                f"Unable to find the reduced mass because the mass of "
-                f"{self.particle} is not available.") from None
-
-        if isinstance(other, (str, int)):
-                other = Particle(other, Z=Z, mass_numb=mass_numb)
-
-        if isinstance(other, Particle):
-            try:
-                mass_that = other.mass.to(u.kg)
-            except MissingAtomicDataError:
-                raise MissingAtomicDataError(
-                    f"Unable to find the reduced mass because the mass of "
-                    f"{other.particle} is not available.") from None
-        else:
-            try:
-                mass_that = other.to(u.kg)
-            except Exception as exc:  # coveralls: ignore
-                raise AtomicError(
-                    f"{other} must be either a Particle or a Quantity or "
-                    f"Constant with units of mass in order to calculate "
-                    f"reduced mass.") from exc
-
-        return (mass_this * mass_that) / (mass_this + mass_that)
+        if self.element:
+            return self._attributes['periodic table']
+        else:  # coveralls: ignore
+            raise InvalidElementError(_category_errmsg(self.particle, 'element'))
 
     @property
     def categories(self) -> Set[str]:
-        """Return the particle's categories."""
+        """Return the particle's categories.
+
+        Examples
+        --------
+        >>> gold = Particle('Au')
+        >>> 'transition metal' in gold.categories
+        True
+        >>> 'antilepton' in gold.categories
+        False
+
+        """
         return self._categories
 
     def is_category(self,
@@ -824,6 +1051,17 @@ def is_category(self,
         `False` if the particle is in any of the excluded categories,
         whether or not the particle matches the other criteria.
 
+        Examples
+        --------
+        >>> Particle('e-').is_category('lepton')
+        True
+        >>> Particle('p+').is_category('baryon', exclude='charged')
+        False
+        >>> Particle('n').is_category({'matter', 'baryon'}, exclude={'charged'})
+        True
+        >>> Particle('mu+').is_category('antilepton', exclude='baryon')
+        True
+
         """
 
         def become_set(arg: Union[str, Set, Tuple, List]) -> Set[str]:
@@ -844,8 +1082,7 @@ def become_set(arg: Union[str, Set, Tuple, List]) -> Set[str]:
                 "No positional arguments are allowed if the `require` keyword "
                 "is set in is_category.")
 
-        require = become_set(category_tuple) if category_tuple else \
-            become_set(require)
+        require = become_set(category_tuple) if category_tuple else become_set(require)
 
         exclude = become_set(exclude)
         any_of = become_set(any_of)
@@ -855,12 +1092,12 @@ def become_set(arg: Union[str, Set, Tuple, List]) -> Set[str]:
 
         invalid_categories = (require | exclude | any_of) - _valid_categories
 
-        duplicate_categories = \
-            require & exclude | exclude & any_of | require & any_of
+        duplicate_categories = require & exclude | exclude & any_of | require & any_of
 
         categories_and_adjectives = [
             (invalid_categories, 'invalid'),
-            (duplicate_categories, 'duplicated')]
+            (duplicate_categories, 'duplicated'),
+        ]
 
         for problem_categories, adjective in categories_and_adjectives:
             if problem_categories:
@@ -876,8 +1113,18 @@ def become_set(arg: Union[str, Set, Tuple, List]) -> Set[str]:
 
         return require <= self._categories
 
+    @property
     def is_electron(self) -> bool:
         """
-        Returns True if the particle is an electron.
+        Return `True` if the particle is an electron, and `False`
+        otherwise.
+
+        Examples
+        --------
+        >>> Particle('e-').is_electron
+        True
+        >>> Particle('e+').is_electron
+        False
+
         """
-        return self.particle == "e-"
+        return self == "e-"
diff --git a/plasmapy/atomic/special_particles.py b/plasmapy/atomic/special_particles.py
index 2043fb02..785303b9 100644
--- a/plasmapy/atomic/special_particles.py
+++ b/plasmapy/atomic/special_particles.py
@@ -6,6 +6,7 @@
 from typing import Set, Dict, List, Optional, Union
 from astropy import units as u, constants as const
 import numpy as np
+from .elements import _PeriodicTable
 
 
 class _ParticleZooClass():
@@ -163,8 +164,8 @@ def _create_Particles_dict() -> Dict[str, dict]:
 
     Particles = dict()
 
-    for thing in ParticleZoo.everything:
-        Particles[thing] = dict()
+    for particle in ParticleZoo.everything:
+        Particles[particle] = dict()
 
     for symbol, name in symbols_and_names:
         Particles[symbol]['name'] = name
@@ -203,46 +204,71 @@ def _create_Particles_dict() -> Dict[str, dict]:
         Particles[antibaryon]['lepton number'] = 0
         Particles[antibaryon]['baryon number'] = -1
 
-    for thing in ParticleZoo.leptons | ParticleZoo.antileptons:
-        if 'e' in thing:
-            Particles[thing]['generation'] = 1
-        elif 'mu' in thing:
-            Particles[thing]['generation'] = 2
-        elif 'tau' in thing:
-            Particles[thing]['generation'] = 3
-
-    for thing in ParticleZoo.leptons | ParticleZoo.antileptons:
-        if 'nu' not in thing:
-            if 'e' in thing:
-                Particles[thing]['mass'] = const.m_e
-            elif 'mu' in thing:
-                Particles[thing]['mass'] = 1.883_531_594e-28 * u.kg
-                Particles[thing]['half-life'] = 2.1969811e-6 * u.s
-            elif 'tau' in thing:
-                Particles[thing]['mass'] = 3.167_47e-27 * u.kg
-                Particles[thing]['half-life'] = 2.906e-13 * u.s
+    for particle in ParticleZoo.leptons | ParticleZoo.antileptons:
+        if 'e' in particle:
+            Particles[particle]['generation'] = 1
+        elif 'mu' in particle:
+            Particles[particle]['generation'] = 2
+        elif 'tau' in particle:
+            Particles[particle]['generation'] = 3
+
+    for particle in ParticleZoo.leptons | ParticleZoo.antileptons:
+        if 'nu' not in particle:
+            if 'e' in particle:
+                Particles[particle]['mass'] = const.m_e
+            elif 'mu' in particle:
+                Particles[particle]['mass'] = 1.883_531_594e-28 * u.kg
+                Particles[particle]['half-life'] = 2.1969811e-6 * u.s
+            elif 'tau' in particle:
+                Particles[particle]['mass'] = 3.167_47e-27 * u.kg
+                Particles[particle]['half-life'] = 2.906e-13 * u.s
 
     # Setting the neutrino mass to None reminds us that, while neutrinos
     # are not massless, we only have upper limits on what the neutrino
     # mass actually is.
 
-    for thing in ParticleZoo.neutrinos | ParticleZoo.antineutrinos:
-        Particles[thing]['mass'] = None
-
-    for thing in ['p+', 'p-']:
-        Particles[thing]['mass'] = const.m_p
-
-    Particles['p+']['integer charge'] = 1
-    Particles['p-']['integer charge'] = -1
-
-    for thing in ['n', 'antineutron']:
-        Particles[thing]['mass'] = const.m_n
-        Particles[thing]['half-life'] = 881.5 * u.s
-        Particles[thing]['integer charge'] = 0
-
-    for thing in ParticleZoo.everything:
-        if 'half-life' not in Particles[thing].keys():
-            Particles[thing]['half-life'] = np.inf * u.s
+    for particle in ParticleZoo.neutrinos | ParticleZoo.antineutrinos:
+        Particles[particle]['mass'] = None
+
+    special_attributes = {
+
+        'p+': {
+            'element': 'H',
+            'atomic number': 1,
+            'mass number': 1,
+            'element name': 'hydrogen',
+            'isotope': 'H-1',
+            'ion': 'p+',
+            'mass': const.m_p,
+            'integer charge': 1,
+            'periodic table': _PeriodicTable(group=1, period=1, block='s', category='nonmetal'),
+        },
+
+        'p-': {
+            'mass': const.m_p,
+            'integer charge': -1,
+        },
+
+        'n': {
+            'mass': const.m_n,
+            'half-life': 881.5 * u.s,
+            'integer charge': 0,
+        },
+
+        'antineutron': {
+            'mass': const.m_n,
+            'half-life': 881.5 * u.s,
+            'integer charge': 0,
+        },
+
+    }
+
+    for particle in special_attributes.keys():
+        Particles[particle] = {**special_attributes[particle], **Particles[particle]}
+
+    for particle in ParticleZoo.everything:
+        if 'half-life' not in Particles[particle].keys():
+            Particles[particle]['half-life'] = np.inf * u.s
 
     for particle in ParticleZoo.particles:
         Particles[particle]['antimatter'] = False


Test patch:
diff --git a/plasmapy/atomic/tests/test_atomic.py b/plasmapy/atomic/tests/test_atomic.py
index d7c83328..1f546ff6 100644
--- a/plasmapy/atomic/tests/test_atomic.py
+++ b/plasmapy/atomic/tests/test_atomic.py
@@ -399,14 +399,14 @@ def test_element_name_error(argument, expected_error):
 def test_standard_atomic_weight_value_between():
     """Test that `standard_atomic_weight` returns approximately the
     correct value for phosphorus."""
-    assert 30.973 < standard_atomic_weight('P').value < 30.974, \
+    assert 30.973 < standard_atomic_weight('P').to(u.u).value < 30.974, \
         "Incorrect standard atomic weight for phosphorus."
 
 
 def test_standard_atomic_weight_unit():
     """Test that `standard_atomic_weight` returns a
     `~astropy.units.Quantity` with the expected units."""
-    assert standard_atomic_weight('Au').unit == u.u, \
+    assert standard_atomic_weight('Au').unit == u.kg, \
         "Incorrect units from standard_atomic_weight for gold."
 
 
@@ -421,7 +421,7 @@ def test_standard_atomic_weight_unit():
 def test_standard_atomic_weight(argument, expected):
     """Test that `standard_atomic_weight` returns the expected values
     for hydrogen."""
-    assert standard_atomic_weight(argument).value == expected, \
+    assert (standard_atomic_weight(argument).to(u.u)).value == expected, \
         f"Incorrect standard_atomic_weight for {repr(argument)}."
 
 
@@ -455,14 +455,14 @@ def test_standard_atomic_weight_error(argument, expected_error):
 
 def test_isotope_mass_berkelium_249():
     """Test that `isotope_mass` returns the correct value for Bk-249."""
-    assert np.isclose(isotope_mass('berkelium-249').value, 249.0749877), \
+    assert np.isclose(isotope_mass('berkelium-249').to(u.u).value, 249.0749877), \
         "Incorrect isotope mass for berkelium."
 
 
 def test_isotope_mass_si_30_units():
     """Test that `isotope_mass` returns a `~astropy.units.Quantity` with
     the correct unit for Si-30."""
-    assert isotope_mass('Si-30').unit == u.u, \
+    assert isotope_mass('Si-30').unit == u.kg, \
         "Incorrect unit for isotope mass for Si-30."
 
 
@@ -900,7 +900,9 @@ def test_isotopic_abundance():
     assert np.isclose(isotopic_abundance('D'), 0.000115)
     assert isotopic_abundance('Be-8') == 0.0, 'Be-8'
     assert isotopic_abundance('Li-8') == 0.0, 'Li-8'
-    assert isotopic_abundance('Og', 294) == 0.0
+
+    with pytest.warns(AtomicWarning):
+        isotopic_abundance('Og', 294)
 
     with pytest.raises(InvalidIsotopeError, message="No exception raised for "
                                                     "neutrons"):
diff --git a/plasmapy/atomic/tests/test_particle_class.py b/plasmapy/atomic/tests/test_particle_class.py
index ae4bfc2c..8d4b9424 100644
--- a/plasmapy/atomic/tests/test_particle_class.py
+++ b/plasmapy/atomic/tests/test_particle_class.py
@@ -56,8 +56,6 @@
       'mass_number': 1,
       'lepton_number': 0,
       'baryon_number': 1,
-      'reduced_mass(Particle("p"))': m_p / 2,
-      'reduced_mass(m_p)': m_p / 2,
       '__str__()': 'p+',
       '__repr__()': 'Particle("p+")',
       'is_category("fermion")': True,
@@ -106,8 +104,6 @@
       'atomic_number': InvalidElementError,
       'lepton_number': 1,
       'baryon_number': 0,
-      'reduced_mass(Particle("e+"))': m_e / 2,
-      'reduced_mass("e-")': m_e / 2,
       '__str__()': 'e-',
       '__repr__()': 'Particle("e-")',
       'binding_energy': InvalidIsotopeError,
@@ -290,14 +286,14 @@
       'is_category(["boson"], exclude=["lepton", "invalid"])': AtomicError,
       'is_category("boson", exclude="boson")': AtomicError,
       'is_category(any_of="boson", exclude="boson")': AtomicError,
-      'reduced_mass("electron")': MissingAtomicDataError,
       }),
 ]
 
 
 @pytest.mark.parametrize("arg, kwargs, expected_dict", test_Particle_table)
 def test_Particle_class(arg, kwargs, expected_dict):
-    """Test that `~plasmapy.atomic.Particle` objects for different
+    """
+    Test that `~plasmapy.atomic.Particle` objects for different
     subatomic particles, elements, isotopes, and ions return the
     expected properties.  Provide a detailed error message that lists
     all of the inconsistencies with the expected results.
@@ -372,8 +368,7 @@ def test_Particle_equivalent_cases(equivalent_particles):
         equivalent_Particle_classes.append(Particle(particle))
 
     for Q in equivalent_Particle_classes[1:]:
-        assert Q == equivalent_Particle_classes[0], \
-            f"{equivalent_particles}"
+        assert Q == equivalent_Particle_classes[0], f"{equivalent_particles}"
 
 
 # arg, kwargs, attribute, exception
@@ -407,10 +402,10 @@ def test_Particle_equivalent_cases(equivalent_particles):
 @pytest.mark.parametrize(
     "arg, kwargs, attribute, exception", test_Particle_error_table)
 def test_Particle_errors(arg, kwargs, attribute, exception):
-    """Test that the appropriate exceptions are raised during the creation
+    """
+    Test that the appropriate exceptions are raised during the creation
     and use of a `~plasmapy.atomic.Particle` object.
     """
-    call = _call_string(arg, kwargs)
     with pytest.raises(exception, message=(
             f"The following command: "
             f"\n\n >>> {_call_string(arg, kwargs)}{attribute}\n\n"
@@ -429,8 +424,10 @@ def test_Particle_errors(arg, kwargs, attribute, exception):
 @pytest.mark.parametrize(
     "arg, kwargs, attribute, warning", test_Particle_warning_table)
 def test_Particle_warnings(arg, kwargs, attribute, warning):
-    """Test that the appropriate warnings are issued during the creation
-    and use of a `~plasmapy.atomic.Particle` object."""
+    """
+    Test that the appropriate warnings are issued during the creation
+    and use of a `~plasmapy.atomic.Particle` object.
+    """
     with pytest.warns(warning, message=(
             f"The following command: "
             f"\n\n >>> {_call_string(arg, kwargs)}{attribute}\n\n"
@@ -446,7 +443,12 @@ def test_Particle_cmp():
 
     assert proton1 == proton2, "Particle('p+') == Particle('proton') is False."
     assert proton1 != electron, "Particle('p+') == Particle('e-') is True."
-    assert not proton1 == 1, "Particle('p+') == 1 is True."
+
+    with pytest.raises(TypeError):
+        electron == 1
+
+    with pytest.raises(AtomicError):
+        electron == 'dfasdf'
 
 
 nuclide_mass_and_mass_equiv_table = [
@@ -462,7 +464,8 @@ def test_Particle_cmp():
 
 @pytest.mark.parametrize('isotope, ion', nuclide_mass_and_mass_equiv_table)
 def test_particle_class_mass_nuclide_mass(isotope: str, ion: str):
-    """Test that the `mass` and `nuclide_mass` attributes return
+    """
+    Test that the `mass` and `nuclide_mass` attributes return
     equivalent values when appropriate.  The inputs should generally be
     an isotope with no charge information, and a fully ionized ion of
     that isotope, in order to make sure that the nuclide mass of the
@@ -503,7 +506,8 @@ def test_particle_class_mass_nuclide_mass(isotope: str, ion: str):
 
 
 def test_particle_half_life_string():
-    """Find the first isotope where the half-life is stored as a string
+    """
+    Find the first isotope where the half-life is stored as a string
     (because the uncertainties are too great), and tests that requesting
     the half-life of that isotope causes a MissingAtomicDataWarning
     whilst returning a string.
@@ -518,7 +522,11 @@ def test_particle_half_life_string():
         assert isinstance(Particle(isotope).half_life, str)
 
 
-@pytest.mark.parametrize("p, is_one", [(Particle('e-'), True),
-                                       (Particle('p+'), False)])
+@pytest.mark.parametrize("p, is_one", [(Particle('e-'), True), (Particle('p+'), False)])
 def test_particle_is_electron(p, is_one):
-    assert p.is_electron() == is_one
+    assert p.is_electron == is_one
+
+
+def test_particle_bool_error():
+    with pytest.raises(AtomicError):
+        bool(Particle('e-'))