Usage¶
How to installing the package¶
Install the project into your Python environment:
$ pip install pythonic-fp-gadgets
Importing the modules¶
Import the gadgets where “gadgets” are simple objects with no external dependencies other than the Python standard library.
from pythonic_fp.gadgets.box import Box
from pythonic_fp.gadgets.iterate_arguments import ita
from pythonic_fp.gadgets.latest_common_ancestor import lca
from pythonic_fp.gadgets.sentinels.flavored import Sentinel
from pythonic_fp.gadgets.sentinels.novalue import NoValue
Use case examples¶
Flavored Sentinels¶
Sentinel values of different (hashable) flavors. Can be used with functions or classes.
Some Use Cases
Could be used like an Enum.
from pythonic_fp.gadgets.sentinels.flavored import Sentinel
def calculate_something(n: int, x: float) -> tuple[Sentinel[int], float]:
if n <= 0:
return (Sentinel(0), x)
return (Sentinel(n), x/n)
def process_result(pair: tuple[Sentinel[int], float]) -> float:
if pair[0] is Sentinel(0):
return 0.0
return pair[1]
result = process_result(calculate_something(213, 15234.541))
Can be also be used as a private implementation detail for a class.
Here is an example of an class that can take an “optional” value
yet still be able to store None as a value.
from typing import cast, ClassVar, Final, overload
from pythonic_fp.gadgets.sentinels.flavored import Sentinel
class MyClass:
_sentinel: Final[ClassVar[Sentinel[str]]] = Sentinel('_secret_str')
@overload
def __init__(self) -> None: ...
@overload
def __init__(self, value: float) -> None: ...
@overload
def __init__(self, value: None) -> None: ...
@overload
def __init__(self, value: float | None) -> None: ...
def __init__(
self, value: float | None | Sentinel[str] = Sentinel('_secret_str')
) -> None:
if value is self._sentinel:
self.value: float | None = 42.0
else:
self.value = cast(float | None, value)
def get_value(self) -> float | None:
return self.value
Sentinel NoValue¶
This test from the test suite is a bit contrived, but I think it illustrates the usage.
from typing import cast, Final, overload
from pythonic_fp.gadgets.sentinels.novalue import NoValue
class Foo:
@overload
def __init__(self, /) -> None: ...
@overload
def __init__(self, repeat: None, /) -> None: ...
def __init__(self, repeat: int | None | NoValue = NoValue(), /) -> None:
if repeat is None:
self._repeat = 0
else:
self._repeat = 1
def repeat(self) -> str:
return 'foo' * self._repeat
class RepeatFoo(Foo):
@overload
def __init__(self, /) -> None: ...
@overload
def __init__(self, repeat: None, /) -> None: ...
@overload
def __init__(self, repeat: int, /) -> None: ...
def __init__(self, repeat: int | None | NoValue = NoValue(), /) -> None:
if repeat is None:
self._repeat = 1
elif repeat is NoValue():
self._repeat = 2
else:
ii: int = cast(int, repeat)
self._repeat = ii if ii >=0 else -ii
def test_foo() -> None:
foo: Foo = Foo()
foo_none: Foo = Foo(None)
assert foo.repeat() == 'foo'
assert foo_none.repeat() == ''
def test_repeat_foo() -> None:
foo: Foo = RepeatFoo()
foo_none: Foo = RepeatFoo(None)
foo_0: Foo = RepeatFoo(0)
foo_1: Foo = RepeatFoo(1)
foo_2: Foo = RepeatFoo(2)
foo_3: Foo = RepeatFoo(3)
foo_neg_4: Foo = RepeatFoo(-4)
assert foo.repeat() == 'foofoo'
assert foo_none.repeat() == 'foo'
assert foo_0.repeat() == ''
assert foo_1.repeat() == 'foo'
assert foo_2.repeat() == 'foofoo'
assert foo_3.repeat() == 'foofoofoo'
assert foo_neg_4.repeat() == 'foofoofoofoo'