Scope of Functions#

Dispatchers#

Consider the following package design.

package/__init__.py:

import a
import b

package/a.py:

from plum import dispatch


@dispatch
def f(x: int):
   return "int"

package/b.py:

from plum import dispatch


@dispatch
def f(x: float):
   return "float"

In a design like this, the methods for f recorded by dispatch are global:

>>> from package.a import f

>>> f(1.0)
'float'

This could be what you want, but it could also be undesirable. In addition, by using the global @dispatch, someone could accidentally overwrite your methods.

other_package/some_file.py:

from plum import dispatch


# If another package happens to also define `f` for an `int`, then that overwrites
# your method!

@dispatch
def f(x: int):
    ...

To prevent this from happening and to keep your functions private, you can create new dispatchers.

package/__init__.py:

import a
import b

package/a.py:

from plum import Dispatcher

dispatch = Dispatcher()


@dispatch
def f(x: int):
   return "int"

package/b.py:

from plum import Dispatcher

dispatch = Dispatcher()


@dispatch
def f(x: float):
   return "float"
>>> from package.a import f

>>> f(1)
'int'

>>> f(1.0)
NotFoundLookupError: For function `f`, `(1.0,)` could not be resolved.

>>> from package.b import f

>>> f(1)
NotFoundLookupError: For function `f`, `(1,)` could not be resolved.

>>> f(1.0)
'float'

Redefinition Warnings#

Whenever you create a dispatcher, you can set warn_redefinition=True to throw a warning whenever a method of a function overwrites another. It is recommended to use this setting.

>>> from plum import Dispatcher

>>> dispatch = Dispatcher(warn_redefinition=True)

>>> @dispatch
... def f(x: int):
...    return x

>>> @dispatch
... def f(x: int):
...    return x

>>> with warnings.catch_warnings(record=True) as w:  
...     f(1)
...     print(w[0].message)
1
`Method(function_name='f', signature=Signature(int), return_type=typing.Any, implementation=<function f at 0x...>)` (`<doctest .../scope.md[0]>:1`) overwrites the earlier definition `Method(function_name='f', signature=Signature(int), return_type=typing.Any, implementation=<function f at 0x...>)` (`<doctest .../scope.md[0]>:1`).

Note that the redefinition warning is thrown whenever the function is run for the first time, because methods are only registered whenever they are needed.