particle_inputο
- plasmapy.particles.decorators.particle_input(
- callable_: Callable[[...], Any] | None = None,
- *,
- require: str | Iterable[str] | None = None,
- any_of: str | Iterable[str] | None = None,
- exclude: str | Iterable[str] | None = None,
- allow_custom_particles: bool = True,
- allow_particle_lists: bool = True,
Convert particle-like arguments into particle objects.
When a callable is decorated with
particle_input(), particle-like arguments that are appropriately annotated (i.e., withParticleLikeorParticleListLike) will be converted into aParticle,CustomParticle, orParticleList.The parameters
Zandmass_numbmay be used to specify the charge number of an ion and mass number of an isotope, respectively, as long asZand/ormass_numbare parameters of the callable and only one parameter is annotated withParticleLikeorParticleListLike.To indicate that
Nonecan be passed to a parameter, annotate it withParticleLike | NoneorParticleListLike | None.If the particle representation does not satisfy any categorization criteria that have been provided, then
particle_input()will raise an exception.If the annotated parameter is named
element,isotope, orion, thenparticle_input()will raise an exception if the argument provided to the callable is not consistent with parameter.Note
An annotated parameter named
ionwill accept neutral atoms andCustomParticle-like objects as long as the charge number is explicitly defined. To enforce that the particle be charged, providerequire={"charged"}toparticle_input().Note
When both
particle_input()andvalidate_quantities()are used to decorate a function, they may be used in either order. When using bothparticle_input()andvalidate_quantities()to decorate an instance method,particle_input()should be the outer decorator andvalidate_quantities()should be the inner decorator (see #2035).import astropy.units as u from plasmapy.particles import particle_input, ParticleLike from plasmapy.utils.decorators.validators import validate_quantities class SomeClass: @particle_input @validate_quantities def instance_method(self, particle: ParticleLike, B: u.Quantity[u.T]): ...
Note
When decorating a class method with
particle_input(),classmethodshould be the outer decorator andparticle_input()should be the inner decorator, and the first argument (representing the class) must be namedcls.- Parameters:
callable (callable, optional) β The function or method to be decorated.
require (
str|set|list|tuple, keyword-only, optional) β Categories that each particle are required to be in.any_of (
str|set|list|tuple, keyword-only, optional) β Categories of which each particle must belong to at least one.exclude (
str|set|list|tuple, keyword-only, optional) β Categories that each particle cannot be in.allow_custom_particles (bool, keyword-only, default:
True) β IfTrue, allowCustomParticleinstances to be passed through.allow_particle_lists (bool, keyword-only, default:
True) β IfTrue, allowParticleListinstances to be passed through.
- Return type:
callable
- Raises:
TypeError β If the annotated argument is not particle-like; or if
Zormass_numbis not an integer.InvalidParticleError β If the annotated argument does not correspond to a valid particle,
allow_custom_particlesisFalseand the argument corresponds to aCustomParticle, orallow_particle_listsisFalseand the argument corresponds to aParticleList.InvalidParticleError β If the decorated argument has charge and/or mass number information, and
Zand/ormass_numbcontain contradictory information.InvalidElementError β If an annotated argument is named
element, and the input does not correspond to an element, isotope, or ion.InvalidIsotopeError β If an annotated argument is named
isotope, and the input does not correspond to an isotope or an ion of an isotope.InvalidIonError β If an annotated argument is named
ion, and the input does not correspond to an ion.ChargeError β If
"charged"is in therequireargument and the particle is not explicitly charged, or ifany_of = {"charged", "uncharged"}and the particle does not have charge information associated with it.ParticleError β If the returned particle(s) do not meet the categorization criteria specified through
require,any_of, orexclude; or if none of the parameters ofcallable_have been appropriately annotated.UnitConversionError β If the annotated argument is a
Quantity, but does not have a physical type of mass or charge.
- Warns:
ParticleWarningβ If decorated argument has charge and/or mass number information, andZand/ormass_numbcontain redundant information.
See also
Notes
There are some known limitations to
particle_input().Particle categorization criteria are not yet applied to arguments that get converted into a
ParticleList(see #2048).This decorator is not compatible with setters (see #2507).
particle_input()has limited compatibility with positional-only, variadic positional, and variadic keyword arguments (see #2150).When
particle_input()andvalidate_quantities()are both used to decorate an instance method on a class,particle_input()must be the outside decorator (see #2035).Because it dynamically changes arguments, functions decorated with
particle_input()often do not work well with static type checkers like mypy. These errors may be silenced by commenting# type: ignore[union-attr]on a line of code, whereunion-attris the name of the mypy error code.
Examples
The
particle_input()decorator takes appropriately annotated particle-like or particle-list-like arguments that are provided tocallable_, and converts them into aParticle,CustomParticle, orParticleListobject.The following decorated function accepts a particle-like input and returns the corresponding particle object.
>>> from plasmapy.particles import particle_input, ParticleLike >>> import astropy.units as u
>>> @particle_input ... def get_particle(particle: ParticleLike): ... return particle
>>> get_particle("p+") Particle("p+") >>> get_particle(["p+", "e-"]) ParticleList(['p+', 'e-']) >>> get_particle(1e-26 * u.kg) CustomParticle(mass=1e-26 kg, charge=nan C)
To allow
Noneto pass, useParticleLike | Noneas the annotation.>>> from typing import Optional >>> @particle_input ... def get_particle_or_none(particle: ParticleLike | None): ... return particle >>> get_particle_or_none("p+") Particle("p+") >>> print(get_particle_or_none(None)) None
If the decorated callable has parameters named
Zand/ormass_numband exactly one annotated parameter, thenZmay be used to provide the charge number andmass_numbmay be used to provide the mass number. MakingZandmass_numbkeyword-only reduces the chances of confusion or mistakes.>>> @particle_input ... def make_particle(particle: ParticleLike, *, Z=None, mass_numb=None): ... return particle >>> make_particle("H", Z=0, mass_numb=3) Particle("T 0+")
Instance methods can also be decorated with
particle_input()as long as the first argument (representing the instance itself) is namedselffollowing standard convention.>>> class SampleClass: ... @particle_input ... def __init__(self, particle: ParticleLike): ... self.particle = particle ... ... @particle_input ... def return_particle(self, new_particle: ParticleLike): ... return new_particle
>>> instance = SampleClass("Ξ±") >>> instance.particle Particle("He-4 2+") >>> instance.return_particle("T+") Particle("T 1+")
The
allow_custom_particlesandallow_particle_listskeyword arguments indicate whethercallable_should acceptCustomParticleandParticleListobjects, respectively.>>> @particle_input(allow_custom_particles=False, allow_particle_lists=False) ... def get_atomic_number(particle: ParticleLike): ... return particle.atomic_number >>> get_atomic_number("Fe") 26
The
require,any_of, andexcludekeyword arguments may be used to specify categorization criteria that a particle must be consistent with. For more details, please refer to the docstring foris_category.>>> @particle_input(require="element", any_of={"charged", "uncharged"}) ... def return_ionic_level(particle: ParticleLike): ... return particle >>> return_ionic_level("Fe-56 0+") Particle("Fe-56 0+")
When the parameter is named
element,isotope, orion, then the corresponding argument must be consistent with the name. When the parameter is namedion, then the particle(s) may also be a neutral atom as long as the charge number is explicitly defined.>>> @particle_input ... def mass_number(isotope: ParticleLike): ... return isotope.mass_number >>> mass_number("D") 2