# Basic functionality


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

## Basics

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L40"
target="_blank" style="float:right; font-size:smaller">source</a>

### ifnone

``` python

def ifnone(
    a, b
):

```

*`b` if `a` is None else `a`*

Since `b if a is None else a` is such a common pattern, we wrap it in a
function. However, be careful, because python will evaluate *both* `a`
and `b` when calling
[`ifnone`](https://fastcore.fast.ai/basics.html#ifnone) (which it
doesn’t do if using the `if` version directly).

``` python
test_eq(ifnone(None,1), 1)
test_eq(ifnone(2   ,1), 2)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L45"
target="_blank" style="float:right; font-size:smaller">source</a>

### maybe_attr

``` python

def maybe_attr(
    o, attr
):

```

*`getattr(o,attr,o)`*

Return the attribute `attr` for object `o`. If the attribute doesn’t
exist, then return the object `o` instead.

``` python
class myobj: myattr='foo'

test_eq(maybe_attr(myobj, 'myattr'), 'foo')
test_eq(maybe_attr(myobj, 'another_attr'), myobj)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L50"
target="_blank" style="float:right; font-size:smaller">source</a>

### basic_repr

``` python

def basic_repr(
    flds:NoneType=None
):

```

*Minimal `__repr__`*

In types which provide rich display functionality in Jupyter, their
`__repr__` is also called in order to provide a fallback text
representation. Unfortunately, this includes a memory address which
changes on every invocation, making it non-deterministic. This causes
diffs to get messy and creates conflicts in git. To fix this, put
`__repr__=basic_repr()` inside your class.

``` python
class SomeClass: __repr__=basic_repr()
repr(SomeClass())
```

    'SomeClass()'

If you pass a list of attributes (`flds`) of an object, then this will
generate a string with the name of each attribute and its corresponding
value. The format of this string is `key=value`, where `key` is the name
of the attribute, and `value` is the value of the attribute. For each
value, attempt to use the `__name__` attribute, otherwise fall back to
using the value’s `__repr__` when constructing the string.

``` python
class SomeClass:
    a=1
    b='foo'
    __repr__=basic_repr('a,b')
    __name__='some-class'

repr(SomeClass())
```

    "SomeClass(a=1, b='foo')"

Nested objects work too:

``` python
class AnotherClass:
    c=SomeClass()
    d='bar'
    __repr__=basic_repr(['c', 'd'])

repr(AnotherClass())
```

    "AnotherClass(c=SomeClass(a=1, b='foo'), d='bar')"

Instance variables (but not class variables) are shown if
[`basic_repr`](https://fastcore.fast.ai/basics.html#basic_repr) is
called with no arguments:

``` python
class SomeClass:
    def __init__(self, a=1, b='foo'): self.a,self.b = a,b
    __repr__=basic_repr()

repr(SomeClass())
```

    "SomeClass(a=1, b='foo')"

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L64"
target="_blank" style="float:right; font-size:smaller">source</a>

### BasicRepr

``` python

def BasicRepr(
    args:VAR_POSITIONAL, kwargs:VAR_KEYWORD
):

```

*Base class for objects needing a basic `__repr__`*

As a shortcut for creating a `__repr__` for instance variables, you can
inherit from
[`BasicRepr`](https://fastcore.fast.ai/basics.html#basicrepr):

``` python
class SomeClass(BasicRepr):
    def __init__(self, a=1, b='foo'): self.a,self.b = a,b

repr(SomeClass())
```

    "SomeClass(a=1, b='foo')"

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L69"
target="_blank" style="float:right; font-size:smaller">source</a>

### is_array

``` python

def is_array(
    x
):

```

*`True` if `x` supports `__array__` or `iloc`*

``` python
is_array(np.array(1)),is_array([1])
```

    (True, False)

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L74"
target="_blank" style="float:right; font-size:smaller">source</a>

### listify

``` python

def listify(
    o:NoneType=None, rest:VAR_POSITIONAL, use_list:bool=False, match:NoneType=None
):

```

*Convert `o` to a `list`*

Conversion is designed to “do what you mean”, e.g:

``` python
test_eq(listify('hi'), ['hi'])
test_eq(listify(b'hi'), [b'hi'])
test_eq(listify(array(1)), [array(1)])
test_eq(listify(1), [1])
test_eq(listify([1,2]), [1,2])
test_eq(listify(range(3)), [0,1,2])
test_eq(listify(None), [])
test_eq(listify(1,2), [1,2])
```

``` python
arr = np.arange(9).reshape(3,3)
listify(arr)
```

    [array([[0, 1, 2],
            [3, 4, 5],
            [6, 7, 8]])]

``` python
listify(array([1,2]))
```

    [array([1, 2])]

Generators are turned into lists too:

``` python
gen = (o for o in range(3))
test_eq(listify(gen), [0,1,2])
```

Use `match` to provide a length to match:

``` python
test_eq(listify(1,match=3), [1,1,1])
```

If `match` is a sequence, it’s length is used:

``` python
test_eq(listify(1,match=range(3)), [1,1,1])
```

If the listified item is not of length `1`, it must be the same length
as `match`:

``` python
test_eq(listify([1,1,1],match=3), [1,1,1])
test_fail(lambda: listify([1,1],match=3))
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L90"
target="_blank" style="float:right; font-size:smaller">source</a>

### tuplify

``` python

def tuplify(
    o, use_list:bool=False, match:NoneType=None
):

```

*Make `o` a tuple*

``` python
test_eq(tuplify(None),())
test_eq(tuplify([1,2,3]),(1,2,3))
test_eq(tuplify(1,match=[1,2,3]),(1,1,1))
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L95"
target="_blank" style="float:right; font-size:smaller">source</a>

### true

``` python

def true(
    x
):

```

*Test whether `x` is truthy; collections with \>0 elements are
considered `True`*

``` python
[(o,true(o)) for o in
 (array(0),array(1),array([0]),array([0,1]),1,0,'',None)]
```

    [(array(0), False),
     (array(1), True),
     (array([0]), True),
     (array([0, 1]), True),
     (1, True),
     (0, False),
     ('', False),
     (None, False)]

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L101"
target="_blank" style="float:right; font-size:smaller">source</a>

### NullType

``` python

def NullType(
    args:VAR_POSITIONAL, kwargs:VAR_KEYWORD
):

```

*An object that is `False` and can be called, chained, and indexed*

``` python
bool(null.hi().there[3])
```

    False

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L111"
target="_blank" style="float:right; font-size:smaller">source</a>

### tonull

``` python

def tonull(
    x
):

```

*Convert `None` to `null`*

``` python
bool(tonull(None).hi().there[3])
```

    False

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L116"
target="_blank" style="float:right; font-size:smaller">source</a>

### get_class

``` python

def get_class(
    nm, fld_names:VAR_POSITIONAL, sup:NoneType=None, doc:NoneType=None, funcs:NoneType=None, anno:NoneType=None,
    flds:VAR_KEYWORD
):

```

*Dynamically create a class, optionally inheriting from `sup`,
containing `fld_names`*

``` python
_t = get_class('_t', 'a', b=2, anno={'b':int})
t = _t()
test_eq(t.a, None)
test_eq(t.b, 2)
t = _t(1, b=3)
test_eq(t.a, 1)
test_eq(t.b, 3)
t = _t(1, 3)
test_eq(t.a, 1)
test_eq(t.b, 3)
test_eq(t, pickle.loads(pickle.dumps(t)))
test_eq(_t.__annotations__, {'b':int, 'a':typing.Any})
repr(t)
```

    '_t(a=1, b=3)'

Most often you’ll want to call
[`mk_class`](https://fastcore.fast.ai/basics.html#mk_class), since it
adds the class to your module. See
[`mk_class`](https://fastcore.fast.ai/basics.html#mk_class) for more
details and examples of use (which also apply to
[`get_class`](https://fastcore.fast.ai/basics.html#get_class)).

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L145"
target="_blank" style="float:right; font-size:smaller">source</a>

### mk_class

``` python

def mk_class(
    nm, fld_names:VAR_POSITIONAL, sup:NoneType=None, doc:NoneType=None, funcs:NoneType=None, mod:NoneType=None,
    anno:NoneType=None, flds:VAR_KEYWORD
):

```

*Create a class using
[`get_class`](https://fastcore.fast.ai/basics.html#get_class) and add to
the caller’s module*

Any `kwargs` will be added as class attributes, and `sup` is an optional
(tuple of) base classes.

``` python
mk_class('_t', a=1, sup=dict)
t = _t()
test_eq(t.a, 1)
assert(isinstance(t,dict))
```

A `__init__` is provided that sets attrs for any `kwargs`, and for any
`args` (matching by position to fields), along with a `__repr__` which
prints all attrs. The docstring is set to `doc`. You can pass `funcs`
which will be added as attrs with the function names.

``` python
def foo(self): return 1
mk_class('_t', 'a', sup=dict, doc='test doc', funcs=foo)

t = _t(3, b=2)
test_eq(t.a, 3)
test_eq(t.b, 2)
test_eq(t.foo(), 1)
test_eq(t.__doc__, 'test doc')
t
```

    {}

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L152"
target="_blank" style="float:right; font-size:smaller">source</a>

### wrap_class

``` python

def wrap_class(
    nm, fld_names:VAR_POSITIONAL, sup:NoneType=None, doc:NoneType=None, funcs:NoneType=None, flds:VAR_KEYWORD
):

```

*Decorator: makes function a method of a new class `nm` passing
parameters to
[`mk_class`](https://fastcore.fast.ai/basics.html#mk_class)*

``` python
@wrap_class('_t', a=2)
def bar(self,x): return x+1

t = _t()
test_eq(t.a, 2)
test_eq(t.bar(3), 4)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L160"
target="_blank" style="float:right; font-size:smaller">source</a>

#### ignore_exceptions

``` python

def ignore_exceptions(
    args:VAR_POSITIONAL, kwargs:VAR_KEYWORD
):

```

*Context manager to ignore exceptions*

``` python
with ignore_exceptions(): 
    # Exception will be ignored
    raise Exception
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L166"
target="_blank" style="float:right; font-size:smaller">source</a>

### exec_local

``` python

def exec_local(
    code, var_name
):

```

*Call `exec` on `code` and return the var `var_name`*

``` python
test_eq(exec_local("a=1", "a"), 1)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L178"
target="_blank" style="float:right; font-size:smaller">source</a>

### risinstance

``` python

def risinstance(
    types, obj:NoneType=None
):

```

*Curried `isinstance` but with args reversed*

``` python
assert risinstance(int, 1)
assert not risinstance(str, 0)
assert risinstance(int)(1)
assert not risinstance(int)(None)
```

`types` can also be strings:

``` python
assert risinstance(('str','int'), 'a')
assert risinstance('str', 'a')
assert not risinstance('int', 'a')
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L185"
target="_blank" style="float:right; font-size:smaller">source</a>

### ver2tuple

``` python

def ver2tuple(
    v:str
)->tuple:

```

*Call self as a function.*

``` python
test_eq(ver2tuple('3.8.1'), (3,8,1))
test_eq(ver2tuple('3.1'), (3,1,0))
test_eq(ver2tuple('3.'), (3,0,0))
test_eq(ver2tuple('3'), (3,0,0))
```

## NoOp

These are used when you need a pass-through function.

------------------------------------------------------------------------

### noop

``` python

def noop(
    x:NoneType=None, args:VAR_POSITIONAL, kwargs:VAR_KEYWORD
):

```

*Do nothing*

``` python
noop()
test_eq(noop(1),1)
```

------------------------------------------------------------------------

### noops

``` python

def noops(
    x:NoneType=None, args:VAR_POSITIONAL, kwargs:VAR_KEYWORD
):

```

*Do nothing (method)*

``` python
class _t: foo=noops
test_eq(_t().foo(1),1)
```

## Infinite Lists

These lists are useful for things like padding an array or adding index
column(s) to arrays.

[`Inf`](https://fastcore.fast.ai/basics.html#inf) defines the following
properties:

- `count: itertools.count()`
- `zeros: itertools.cycle([0])`
- `ones : itertools.cycle([1])`
- `nones: itertools.cycle([None])`

``` python
test_eq([o for i,o in zip(range(5), Inf.count)],
        [0, 1, 2, 3, 4])

test_eq([o for i,o in zip(range(5), Inf.zeros)],
        [0]*5)

test_eq([o for i,o in zip(range(5), Inf.ones)],
        [1]*5)

test_eq([o for i,o in zip(range(5), Inf.nones)],
        [None]*5)
```

## Operator Functions

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L217"
target="_blank" style="float:right; font-size:smaller">source</a>

### in\_

``` python

def in_(
    x, a
):

```

*`True` if `x in a`*

``` python
# test if element is in another
assert in_('c', ('b', 'c', 'a'))
assert in_(4, [2,3,4,5])
assert in_('t', 'fastai')
test_fail(in_('h', 'fastai'))

# use in_ as a partial
assert in_('fastai')('t')
assert in_([2,3,4,5])(4)
test_fail(in_('fastai')('h'))
```

In addition to [`in_`](https://fastcore.fast.ai/basics.html#in_), the
following functions are provided matching the behavior of the equivalent
versions in `operator`: *lt gt le ge eq ne add sub mul truediv is\_
is_not mod*.

``` python
lt(3,5),gt(3,5),is_(None,None),in_(0,[1,2]),mod(3,2)
```

    (True, False, True, False, 1)

Similarly to `_in`, they also have additional functionality: if you only
pass one param, they return a partial function that passes that param as
the second positional parameter.

``` python
lt(5)(3),gt(5)(3),is_(None)(None),in_([1,2])(0),mod(2)(3)
```

    (True, False, True, False, 1)

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L230"
target="_blank" style="float:right; font-size:smaller">source</a>

### ret_true

``` python

def ret_true(
    args:VAR_POSITIONAL, kwargs:VAR_KEYWORD
):

```

*Predicate: always `True`*

``` python
assert ret_true(1,2,3)
assert ret_true(False)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L235"
target="_blank" style="float:right; font-size:smaller">source</a>

### ret_false

``` python

def ret_false(
    args:VAR_POSITIONAL, kwargs:VAR_KEYWORD
):

```

*Predicate: always `False`*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L240"
target="_blank" style="float:right; font-size:smaller">source</a>

### stop

``` python

def stop(
    e:type=StopIteration
):

```

*Raises exception `e` (by default `StopIteration`)*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L245"
target="_blank" style="float:right; font-size:smaller">source</a>

### gen

``` python

def gen(
    func, seq, cond:function=ret_true
):

```

*Like `(func(o) for o in seq if cond(func(o)))` but handles
`StopIteration`*

``` python
test_eq(gen(noop, Inf.count, lt(5)),
        range(5))
test_eq(gen(operator.neg, Inf.count, gt(-5)),
        [0,-1,-2,-3,-4])
test_eq(gen(lambda o:o if o<5 else stop(), Inf.count),
        range(5))
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L250"
target="_blank" style="float:right; font-size:smaller">source</a>

### chunked

``` python

def chunked(
    it, chunk_sz:NoneType=None, drop_last:bool=False, n_chunks:NoneType=None, pad:bool=False, pad_val:NoneType=None
):

```

*Return batches from iterator `it` of size `chunk_sz` (or return
`n_chunks` total)*

Note that you must pass either `chunk_sz`, or `n_chunks`, but not both.

``` python
t = list(range(10))
test_eq(chunked(t,3),      [[0,1,2], [3,4,5], [6,7,8], [9]])
test_eq(chunked(t,3,True), [[0,1,2], [3,4,5], [6,7,8],    ])

t = map(lambda o:stop() if o==6 else o, Inf.count)
test_eq(chunked(t,3), [[0, 1, 2], [3, 4, 5]])
t = map(lambda o:stop() if o==7 else o, Inf.count)
test_eq(chunked(t,3), [[0, 1, 2], [3, 4, 5], [6]])

t = np.arange(10)
test_eq(chunked(t,3),      [[0,1,2], [3,4,5], [6,7,8], [9]])
test_eq(chunked(t,3,True), [[0,1,2], [3,4,5], [6,7,8],    ])

test_eq(chunked([], 3),          [])
test_eq(chunked([], n_chunks=3), [])
```

Pass `pad=True` and an optional `pad_val` to pad the last chunk:

``` python
t = list(range(10))
test_eq(chunked(t,3,pad=True), [[0,1,2], [3,4,5], [6,7,8], [9,None,None]])
test_eq(chunked(t,3,pad=True,pad_val=0), [[0,1,2], [3,4,5], [6,7,8], [9,0,0]])
test_eq(chunked(t,4,pad=True,pad_val=-1), [[0,1,2,3], [4,5,6,7], [8,9,-1,-1]])
test_eq(chunked(range(5),2,pad=True), [[0,1], [2,3], [4,None]])
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L263"
target="_blank" style="float:right; font-size:smaller">source</a>

### otherwise

``` python

def otherwise(
    x, tst, y
):

```

*`y if tst(x) else x`*

``` python
test_eq(otherwise(2+1, gt(3), 4), 3)
test_eq(otherwise(2+1, gt(2), 4), 4)
```

## Attribute Helpers

These functions reduce boilerplate when setting or manipulating
attributes or properties of objects.

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L268"
target="_blank" style="float:right; font-size:smaller">source</a>

### custom_dir

``` python

def custom_dir(
    c, add
):

```

*Implement custom `__dir__`, adding `add` to `cls`*

[`custom_dir`](https://fastcore.fast.ai/basics.html#custom_dir) allows
you extract the [`__dict__` property of a
class](https://stackoverflow.com/questions/19907442/explain-dict-attribute)
and appends the list `add` to it.

``` python
class _T: 
    def f(): pass

s = custom_dir(_T(), add=['foo', 'bar'])
assert {'foo', 'bar', 'f'}.issubset(s)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L273"
target="_blank" style="float:right; font-size:smaller">source</a>

### adict

``` python

def adict(
    args:VAR_POSITIONAL, kwargs:VAR_KEYWORD
):

```

*`dict` subclass that also provides access to keys as attrs*

``` python
d = adict(a=1,b="two")
test_eq(d.a, 1)
test_eq(d['b'], 'two')
test_eq(d.get('c','nope'), 'nope')
d.b = 2
test_eq(d.b, 2)
test_eq(d['b'], 2)
d['b'] = 3
test_eq(d['b'], 3)
test_eq(d.b, 3)
assert 'a' in dir(d)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L280"
target="_blank" style="float:right; font-size:smaller">source</a>

### AttrDict

``` python

def AttrDict(
    args:VAR_POSITIONAL, kwargs:VAR_KEYWORD
):

```

*`dict` subclass that also provides access to keys as attrs, and has a
pretty markdown repr*

[`AttrDict`](https://fastcore.fast.ai/basics.html#attrdict) will pretty
print in Jupyter Notebooks:

``` python
d = AttrDict(a=1,b="two")

_test_dict = {'a':1, 'b': {'c':1, 'd':2}, 'c': {'c':1, 'd':2}, 'd': {'c':1, 'd':2},
              'e': {'c':1, 'd':2}, 'f': {'c':1, 'd':2, 'e': 4, 'f':[1,2,3,4,5]}}
AttrDict(_test_dict)
```

<div class="prose" markdown="1">

``` python
{ 'a': 1,
  'b': {'c': 1, 'd': 2},
  'c': {'c': 1, 'd': 2},
  'd': {'c': 1, 'd': 2},
  'e': {'c': 1, 'd': 2},
  'f': {'c': 1, 'd': 2, 'e': 4, 'f': [1, 2, 3, 4, 5]}}
```

</div>

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L289"
target="_blank" style="float:right; font-size:smaller">source</a>

### AttrDictDefault

``` python

def AttrDictDefault(
    args:VAR_POSITIONAL, default_:NoneType=None, kwargs:VAR_KEYWORD
):

```

*[`AttrDict`](https://fastcore.fast.ai/basics.html#attrdict) subclass
that returns `default_` for missing attrs*

``` python
d = AttrDictDefault(a=1,b="two", default_='nope')
test_eq(d.a, 1)
test_eq(d['b'], 'two')
test_eq(d.c, 'nope')
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L298"
target="_blank" style="float:right; font-size:smaller">source</a>

### NS

``` python

def NS(
    args:VAR_POSITIONAL, kwargs:VAR_KEYWORD
):

```

*`SimpleNamespace` subclass that also adds `iter` and `dict` support*

This is very similar to
[`AttrDict`](https://fastcore.fast.ai/basics.html#attrdict), but since
it starts with `SimpleNamespace`, it has some differences in behavior.
You can use it just like `SimpleNamespace`:

``` python
d = NS(**_test_dict)
d
```

    namespace(a=1,
              b={'c': 1, 'd': 2},
              c={'c': 1, 'd': 2},
              d={'c': 1, 'd': 2},
              e={'c': 1, 'd': 2},
              f={'c': 1, 'd': 2, 'e': 4, 'f': [1, 2, 3, 4, 5]})

…but you can also index it to get/set:

``` python
d['a']
```

    1

…and iterate t:

``` python
list(d)
```

    ['a', 'b', 'c', 'd', 'e', 'f']

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L305"
target="_blank" style="float:right; font-size:smaller">source</a>

### get_annotations_ex

``` python

def get_annotations_ex(
    obj, globals:NoneType=None, locals:NoneType=None
):

```

*Backport of py3.10 `get_annotations` that returns globals/locals*

In Python 3.10 `inspect.get_annotations` was added. However previous
versions of Python are unable to evaluate type annotations correctly if
`from future import __annotations__` is used. Furthermore, *all*
annotations are evaluated, even if only some subset are needed.
[`get_annotations_ex`](https://fastcore.fast.ai/basics.html#get_annotations_ex)
provides the same functionality as `inspect.get_annotations`, but works
on earlier versions of Python, and returns the `globals` and `locals`
needed to evaluate types.

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L352"
target="_blank" style="float:right; font-size:smaller">source</a>

### eval_type

``` python

def eval_type(
    t, glb, loc
):

```

*`eval` a type or collection of types, if needed, for annotations in
py3.10+*

In py3.10, or if `from future import __annotations__` is used, `a` is a
`str`:

``` python
class _T2a: pass
def func(a: _T2a): pass
ann,glb,loc = get_annotations_ex(func)

eval_type(ann['a'], glb, loc)
```

    __main__._T2a

`|` is supported for defining `Union` types when using
[`eval_type`](https://fastcore.fast.ai/basics.html#eval_type) even for
python versions prior to 3.9:

``` python
class _T2b: pass
def func(a: _T2a|_T2b): pass
ann,glb,loc = get_annotations_ex(func)

eval_type(ann['a'], glb, loc)
```

    __main__._T2a | __main__._T2b

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L369"
target="_blank" style="float:right; font-size:smaller">source</a>

### type_hints

``` python

def type_hints(
    f
):

```

*Like `typing.get_type_hints` but returns `{}` if not allowed type*

``` python
def type_hints(f):
    "Like `typing.get_type_hints` but returns `{}` if not allowed type"
    if not isinstance(f, _allowed_types): return {}
    ann,glb,loc = get_annotations_ex(f)
    return {k:_eval_type(v,glb,loc) for k,v in ann.items()}
```

For example, type `func` is allowed so
[`type_hints`](https://fastcore.fast.ai/basics.html#type_hints) returns
the same value as `typing.get_hints`:

``` python
def f(a:int)->bool: ... # a function with type hints (allowed)
exp = {'a':int,'return':bool}
test_eq(type_hints(f), typing.get_type_hints(f))
test_eq(type_hints(f), exp)
```

However, `class` is not an allowed type, so
[`type_hints`](https://fastcore.fast.ai/basics.html#type_hints) returns
`{}`:

``` python
class _T:
    def __init__(self, a:int=0)->bool: ...
assert not type_hints(_T)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L376"
target="_blank" style="float:right; font-size:smaller">source</a>

### annotations

``` python

def annotations(
    o
):

```

*Annotations for `o`, or `type(o)`*

This supports a wider range of situations than
[`type_hints`](https://fastcore.fast.ai/basics.html#type_hints), by
checking `type()` and `__init__` for annotations too:

``` python
for o in _T,_T(),_T.__init__,f: test_eq(annotations(o), exp)
assert not annotations(int)
assert not annotations(print)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L386"
target="_blank" style="float:right; font-size:smaller">source</a>

### anno_ret

``` python

def anno_ret(
    func
):

```

*Get the return annotation of `func`*

``` python
def f(x) -> float: return x
test_eq(anno_ret(f), float)

def f(x) -> typing.Tuple[float,float]: return x
assert anno_ret(f)==typing.Tuple[float,float]
```

If your return annotation is `None`,
[`anno_ret`](https://fastcore.fast.ai/basics.html#anno_ret) will return
`NoneType` (and not `None`):

``` python
def f(x) -> None: return x

test_eq(anno_ret(f), NoneType)
assert anno_ret(f) is not None # returns NoneType instead of None
```

If your function does not have a return type, or if you pass in `None`
instead of a function, then
[`anno_ret`](https://fastcore.fast.ai/basics.html#anno_ret) returns
`None`:

``` python
def f(x): return x

test_eq(anno_ret(f), None)
test_eq(anno_ret(None), None) # instead of passing in a func, pass in None
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L393"
target="_blank" style="float:right; font-size:smaller">source</a>

### signature_ex

``` python

def signature_ex(
    obj, eval_str:bool=False
):

```

*Backport of `inspect.signature(..., eval_str=True` to \<py310*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L410"
target="_blank" style="float:right; font-size:smaller">source</a>

### union2tuple

``` python

def union2tuple(
    t
):

```

*Call self as a function.*

``` python
test_eq(union2tuple(Union[int,str]), (int,str))
test_eq(union2tuple(int), int)
assert union2tuple(Tuple[int,str])==Tuple[int,str]
test_eq(union2tuple((int,str)), (int,str))
if UnionType: test_eq(union2tuple(int|str), (int,str))
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L416"
target="_blank" style="float:right; font-size:smaller">source</a>

### argnames

``` python

def argnames(
    f, frame:bool=False
):

```

*Names of arguments to function or frame `f`*

``` python
test_eq(argnames(f), ['x'])
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L422"
target="_blank" style="float:right; font-size:smaller">source</a>

### with_cast

``` python

def with_cast(
    f
):

```

*Decorator which uses any parameter annotations as preprocessing
functions*

``` python
@with_cast
def _f(a, b:Path, c:str='', d=0): return (a,b,c,d)

test_eq(_f(1, '.', 3), (1,Path('.'),'3',0))
test_eq(_f(1, '.'), (1,Path('.'),'',0))

@with_cast
def _g(a:int=0)->str: return a

test_eq(_g(4.0), '4')
test_eq(_g(4.4), '4')
test_eq(_g(2), '2')
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L448"
target="_blank" style="float:right; font-size:smaller">source</a>

### store_attr

``` python

def store_attr(
    names:NoneType=None, but:str='', cast:bool=False, store_args:NoneType=None, attrs:VAR_KEYWORD
):

```

*Store params named in comma-separated `names` from calling context into
attrs in `self`*

In it’s most basic form, you can use
[`store_attr`](https://fastcore.fast.ai/basics.html#store_attr) to
shorten code like this:

``` python
class T:
    def __init__(self, a,b,c): self.a,self.b,self.c = a,b,c
```

…to this:

``` python
class T:
    def __init__(self, a,b,c): store_attr('a,b,c', self)
```

This class behaves as if we’d used the first form:

``` python
t = T(1,c=2,b=3)
assert t.a==1 and t.b==3 and t.c==2
```

``` python
class T1:
    def __init__(self, a,b,c): store_attr()
```

In addition, it stores the attrs as a `dict` in `__stored_args__`, which
you can use for display, logging, and so forth.

``` python
test_eq(t.__stored_args__, {'a':1, 'b':3, 'c':2})
```

Since you normally want to use the first argument (often called `self`)
for storing attributes, it’s optional:

``` python
class T:
    def __init__(self, a,b,c:str): store_attr('a,b,c')

t = T(1,c=2,b=3)
assert t.a==1 and t.b==3 and t.c==2
```

With `cast=True` any parameter annotations will be used as preprocessing
functions for the corresponding arguments:

``` python
class T:
    def __init__(self, a:listify, b, c:str): store_attr('a,b,c', cast=True)

t = T(1,c=2,b=3)
assert t.a==[1] and t.b==3 and t.c=='2'
```

You can inherit from a class using
[`store_attr`](https://fastcore.fast.ai/basics.html#store_attr), and
just call it again to add in any new attributes added in the derived
class:

``` python
class T2(T):
    def __init__(self, d, **kwargs):
        super().__init__(**kwargs)
        store_attr('d')

t = T2(d=1,a=2,b=3,c=4)
assert t.a==2 and t.b==3 and t.c==4 and t.d==1
```

You can skip passing a list of attrs to store. In this case, all
arguments passed to the method are stored:

``` python
class T:
    def __init__(self, a,b,c): store_attr()

t = T(1,c=2,b=3)
assert t.a==1 and t.b==3 and t.c==2
```

``` python
class T4(T):
    def __init__(self, d, **kwargs):
        super().__init__(**kwargs)
        store_attr()

t = T4(4, a=1,c=2,b=3)
assert t.a==1 and t.b==3 and t.c==2 and t.d==4
```

``` python
class T4:
    def __init__(self, *, a: int, b: float = 1):
        store_attr()
        
t = T4(a=3)
assert t.a==3 and t.b==1
t = T4(a=3, b=2)
assert t.a==3 and t.b==2
```

You can skip some attrs by passing `but`:

``` python
class T:
    def __init__(self, a,b,c): store_attr(but='a')

t = T(1,c=2,b=3)
assert t.b==3 and t.c==2
assert not hasattr(t,'a')
```

You can also pass keywords to
[`store_attr`](https://fastcore.fast.ai/basics.html#store_attr), which
is identical to setting the attrs directly, but also stores them in
`__stored_args__`.

``` python
class T:
    def __init__(self): store_attr(a=1)

t = T()
assert t.a==1
```

You can also use store_attr inside functions.

``` python
def create_T(a, b):
    t = SimpleNamespace()
    store_attr(self=t)
    return t

t = create_T(a=1, b=2)
assert t.a==1 and t.b==2
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L466"
target="_blank" style="float:right; font-size:smaller">source</a>

### attrdict

``` python

def attrdict(
    o, ks:VAR_POSITIONAL, default:NoneType=None
):

```

*Dict from each `k` in `ks` to `getattr(o,k)`*

``` python
class T:
    def __init__(self, a,b,c): store_attr()

t = T(1,c=2,b=3)
test_eq(attrdict(t,'b','c'), {'b':3, 'c':2})
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L471"
target="_blank" style="float:right; font-size:smaller">source</a>

### properties

``` python

def properties(
    cls, ps:VAR_POSITIONAL
):

```

*Change attrs in `cls` with names in `ps` to properties*

``` python
class T:
    def a(self): return 1
    def b(self): return 2
properties(T,'a')

test_eq(T().a,1)
test_eq(T().b(),2)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L481"
target="_blank" style="float:right; font-size:smaller">source</a>

### camel2words

``` python

def camel2words(
    s, space:str=' '
):

```

*Convert CamelCase to ‘spaced words’*

``` python
test_eq(camel2words('ClassAreCamel'), 'Class Are Camel')
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L486"
target="_blank" style="float:right; font-size:smaller">source</a>

### camel2snake

``` python

def camel2snake(
    name
):

```

*Convert CamelCase to snake_case*

``` python
test_eq(camel2snake('ClassAreCamel'), 'class_are_camel')
test_eq(camel2snake('Already_Snake'), 'already__snake')
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L492"
target="_blank" style="float:right; font-size:smaller">source</a>

### snake2camel

``` python

def snake2camel(
    s
):

```

*Convert snake_case to CamelCase*

``` python
test_eq(snake2camel('a_b_cc'), 'ABCc')
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L497"
target="_blank" style="float:right; font-size:smaller">source</a>

### class2attr

``` python

def class2attr(
    cls_name
):

```

*Return the snake-cased name of the class; strip ending `cls_name` if it
exists.*

``` python
class Parent:
    @property
    def name(self): return class2attr(self, 'Parent')

class ChildOfParent(Parent): pass
class ParentChildOf(Parent): pass

p = Parent()
cp = ChildOfParent()
cp2 = ParentChildOf()

test_eq(p.name, 'parent')
test_eq(cp.name, 'child_of')
test_eq(cp2.name, 'parent_child_of')
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L502"
target="_blank" style="float:right; font-size:smaller">source</a>

### getcallable

``` python

def getcallable(
    o, attr
):

```

*Calls `getattr` with a default of `noop`*

``` python
class Math:
    def addition(self,a,b): return a+b

m = Math()

test_eq(getcallable(m, "addition")(a=1,b=2), 3)
test_eq(getcallable(m, "subtraction")(a=1,b=2), None)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L507"
target="_blank" style="float:right; font-size:smaller">source</a>

### getattrs

``` python

def getattrs(
    o, attrs:VAR_POSITIONAL, default:NoneType=None
):

```

*List of all `attrs` in `o`*

``` python
from fractions import Fraction
```

``` python
getattrs(Fraction(1,2), 'numerator', 'denominator')
```

    [1, 2]

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L512"
target="_blank" style="float:right; font-size:smaller">source</a>

### hasattrs

``` python

def hasattrs(
    o, attrs
):

```

*Test whether `o` contains all `attrs`*

``` python
assert hasattrs(1,('imag','real'))
assert not hasattrs(1,('imag','foo'))
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L517"
target="_blank" style="float:right; font-size:smaller">source</a>

### setattrs

``` python

def setattrs(
    dest, flds, src
):

```

*Call self as a function.*

``` python
d = dict(a=1,bb="2",ignore=3)
o = SimpleNamespace()
setattrs(o, "a,bb", d)
test_eq(o.a, 1)
test_eq(o.bb, "2")
```

``` python
d = SimpleNamespace(a=1,bb="2",ignore=3)
o = SimpleNamespace()
setattrs(o, "a,bb", d)
test_eq(o.a, 1)
test_eq(o.bb, "2")
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L523"
target="_blank" style="float:right; font-size:smaller">source</a>

### try_attrs

``` python

def try_attrs(
    obj, attrs:VAR_POSITIONAL
):

```

*Return first attr that exists in `obj`*

``` python
test_eq(try_attrs(1, 'real'), 1)
test_eq(try_attrs(1, 'foobar', 'real'), 1)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L531"
target="_blank" style="float:right; font-size:smaller">source</a>

### DepProp

``` python

def DepProp(
    fchange, fnorm:NoneType=None
):

```

*Property decorator with dependency update triggering*

[`DepProp`](https://fastcore.fast.ai/basics.html#depprop) is a
descriptor that stores a value and calls a “change” function whenever
that value changes or is deleted. This is useful for invalidating caches
or triggering side effects when a dependency is updated. An optional
normalizer can preprocess values before storage.

``` python
class Square:
    @DepProp
    def width(self): self._area_cache = None

    @property
    def area(self):
        if self._area_cache is None: self._area_cache = self.width**2
        return self._area_cache

r = Square()
r.width = 3
test_eq(r.area, 9)
r.width = 5  # cache cleared automatically
test_eq(r.area, 25)
```

Use the `.norm` decorator to add a normalizer that preprocesses values
before storage:

``` python
class T:
    @DepProp
    def name(self): self.log = f'changed to {self.name}'

    @name.norm
    def name(self, v): return v.strip().lower()

t = T()
t.name = '  Hello '
test_eq(t.name, 'hello')
test_eq(t.log, 'changed to hello')
```

Setting the same value again does *not* trigger the change function:

``` python
t.log = 'not called'
t.name = 'hello'  # same value -- no change
test_eq(t.log, 'not called')
```

Deleting the property removes the backing attribute and calls `fchange`:

``` python
del t.name
test_eq(t.log, 'changed to None')
test_eq(t.name, None)
```

## Attribute Delegation

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L556"
target="_blank" style="float:right; font-size:smaller">source</a>

### GetAttrBase

``` python

def GetAttrBase(
    args:VAR_POSITIONAL, kwargs:VAR_KEYWORD
):

```

*Basic delegation of
[`__getattr__`](https://fastcore.fast.ai/xml.html#__getattr__) and
`__dir__`*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L565"
target="_blank" style="float:right; font-size:smaller">source</a>

#### GetAttr

``` python

def GetAttr(
    args:VAR_POSITIONAL, kwargs:VAR_KEYWORD
):

```

*Inherit from this to have all attr accesses in `self._xtra` passed down
to `self.default`*

Inherit from [`GetAttr`](https://fastcore.fast.ai/basics.html#getattr)
to have attr access passed down to an instance attribute. This makes it
easy to create composites that don’t require callers to know about their
components. For a more detailed discussion of how this works as well as
relevant context, we suggest reading the [delegated composition section
of this blog article](https://www.fast.ai/2019/08/06/delegation/).

You can customise the behaviour of
[`GetAttr`](https://fastcore.fast.ai/basics.html#getattr) in subclasses
via; - `_default` - By default, this is set to `'default'`, so attr
access is passed down to `self.default` - `_default` can be set to the
name of any instance attribute that does not start with dunder `__` -
`_xtra` - By default, this is `None`, so all attr access is passed
down - You can limit which attrs get passed down by setting `_xtra` to a
list of attribute names

To illuminate the utility of
[`GetAttr`](https://fastcore.fast.ai/basics.html#getattr), suppose we
have the following two classes, `_WebPage` which is a superclass of
`_ProductPage`, which we wish to compose like so:

``` python
class _WebPage:
    def __init__(self, title, author="Jeremy"):
        self.title,self.author = title,author

class _ProductPage:
    def __init__(self, page, price): self.page,self.price = page,price
        
page = _WebPage('Soap', author="Sylvain")
p = _ProductPage(page, 15.0)
```

How do we make it so we can just write `p.author`, instead of
`p.page.author` to access the `author` attribute? We can use
[`GetAttr`](https://fastcore.fast.ai/basics.html#getattr), of course!
First, we subclass
[`GetAttr`](https://fastcore.fast.ai/basics.html#getattr) when defining
`_ProductPage`. Next, we set `self.default` to the object whose
attributes we want to be able to access directly, which in this case is
the `page` argument passed on initialization:

``` python
class _ProductPage(GetAttr):
    def __init__(self, page, price): self.default,self.price = page,price #self.default allows you to access page directly.

p = _ProductPage(page, 15.0)
```

Now, we can access the `author` attribute directly from the instance:

``` python
test_eq(p.author, 'Sylvain')
```

If you wish to store the object you are composing in an attribute other
than `self.default`, you can set the class attribute `_data` as shown
below. This is useful in the case where you might have a name collision
with `self.default`:

``` python
class _C(GetAttr):
    _default = '_data' # use different component name; `self._data` rather than `self.default`
    def __init__(self,a): self._data = a
    def foo(self): noop

t = _C('Hi')
test_eq(t._data, 'Hi') 
test_fail(lambda: t.default) # we no longer have self.default
test_eq(t.lower(), 'hi')
test_eq(t.upper(), 'HI')
assert 'lower' in dir(t)
assert 'upper' in dir(t)
```

By default, all attributes and methods of the object you are composing
are retained. In the below example, we compose a `str` object with the
class `_C`. This allows us to directly call string methods on instances
of class `_C`, such as `str.lower()` or `str.upper()`:

``` python
class _C(GetAttr):
    # allow all attributes and methods to get passed to `self.default` (by leaving _xtra=None)
    def __init__(self,a): self.default = a
    def foo(self): noop

t = _C('Hi')
test_eq(t.lower(), 'hi')
test_eq(t.upper(), 'HI')
assert 'lower' in dir(t)
assert 'upper' in dir(t)
```

However, you can choose which attributes or methods to retain by
defining a class attribute `_xtra`, which is a list of allowed attribute
and method names to delegate. In the below example, we only delegate the
`lower` method from the composed `str` object when defining class `_C`:

``` python
class _C(GetAttr):
    _xtra = ['lower'] # specify which attributes get passed to `self.default`
    def __init__(self,a): self.default = a
    def foo(self): noop

t = _C('Hi')
test_eq(t.default, 'Hi')
test_eq(t.lower(), 'hi')
test_fail(lambda: t.upper()) # upper wasn't in _xtra, so it isn't available to be called
assert 'lower' in dir(t)
assert 'upper' not in dir(t)
```

You must be careful to properly set an instance attribute in `__init__`
that corresponds to the class attribute `_default`. The below example
sets the class attribute `_default` to `data`, but erroneously fails to
define `self.data` (and instead defines `self.default`).

Failing to properly set instance attributes leads to errors when you try
to access methods directly:

``` python
class _C(GetAttr):
    _default = 'data' # use a bad component name; i.e. self.data does not exist
    def __init__(self,a): self.default = a
    def foo(self): noop
        
# TODO: should we raise an error when we create a new instance ...
t = _C('Hi')
test_eq(t.default, 'Hi')
# ... or is it enough for all GetAttr features to raise errors
test_fail(lambda: t.data)
test_fail(lambda: t.lower())
test_fail(lambda: t.upper())
test_fail(lambda: dir(t))
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L583"
target="_blank" style="float:right; font-size:smaller">source</a>

### delegate_attr

``` python

def delegate_attr(
    k, to
):

```

*Use in [`__getattr__`](https://fastcore.fast.ai/xml.html#__getattr__)
to delegate to attr `to` without inheriting from
[`GetAttr`](https://fastcore.fast.ai/basics.html#getattr)*

[`delegate_attr`](https://fastcore.fast.ai/basics.html#delegate_attr) is
a functional way to delegate attributes, and is an alternative to
[`GetAttr`](https://fastcore.fast.ai/basics.html#getattr). We recommend
reading the documentation of
[`GetAttr`](https://fastcore.fast.ai/basics.html#getattr) for more
details around delegation.

You can use achieve delegation when you define
[`__getattr__`](https://fastcore.fast.ai/xml.html#__getattr__) by using
[`delegate_attr`](https://fastcore.fast.ai/basics.html#delegate_attr):

``` python
class _C:
    def __init__(self, o): self.o = o # self.o corresponds to the `to` argument in delegate_attr.
    def __getattr__(self, k): return delegate_attr(self, k, to='o')
    

t = _C('HELLO') # delegates to a string
test_eq(t.lower(), 'hello')

t = _C(np.array([5,4,3])) # delegates to a numpy array
test_eq(t.sum(), 12)

t = _C(pd.DataFrame({'a': [1,2], 'b': [3,4]})) # delegates to a pandas.DataFrame
test_eq(t.b.max(), 4)
```

## Extensible Types

[`ShowPrint`](https://fastcore.fast.ai/basics.html#showprint) is a base
class that defines a `show` method, which is used primarily for
callbacks in fastai that expect this method to be defined.

[`Int`](https://fastcore.fast.ai/basics.html#int),
[`Float`](https://fastcore.fast.ai/basics.html#float), and
[`Str`](https://fastcore.fast.ai/basics.html#str) extend `int`, `float`
and `str` respectively by adding an additional `show` method by
inheriting from
[`ShowPrint`](https://fastcore.fast.ai/basics.html#showprint).

The code for [`Int`](https://fastcore.fast.ai/basics.html#int) is shown
below:

Examples:

``` python
Int(0).show()
Float(2.0).show()
Str('Hello').show()
```

    0
    2.0
    Hello

## Collection functions

Functions that manipulate popular python collections.

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L608"
target="_blank" style="float:right; font-size:smaller">source</a>

### partition

``` python

def partition(
    coll, f
):

```

*Partition a collection by a predicate*

``` python
ts,fs = partition(range(10), mod(2))
test_eq(fs, [0,2,4,6,8])
test_eq(ts, [1,3,5,7,9])
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L618"
target="_blank" style="float:right; font-size:smaller">source</a>

### partition_dict

``` python

def partition_dict(
    d, f
):

```

*Partition a dict by a predicate that takes key/value params*

``` python
d = {'a':1, 'b':2, 'c':3, 'd':4}
ts,fs = partition_dict(d, lambda k,v: v%2)
test_eq(fs, {'b':2, 'd':4})
test_eq(ts, {'a':1, 'c':3})
```

``` python
ts,fs = partition_dict(d, lambda k,v: k in 'bc')
test_eq(ts, {'b':2, 'c':3})
test_eq(fs, {'a':1, 'd':4})
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L625"
target="_blank" style="float:right; font-size:smaller">source</a>

### flatten

``` python

def flatten(
    o
):

```

*Concatenate all collections and items as a generator*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L633"
target="_blank" style="float:right; font-size:smaller">source</a>

### concat

``` python

def concat(
    colls
)->list:

```

*Concatenate all collections and items as a list*

``` python
concat([(o for o in range(2)),[2,3,4], 5])
```

    [0, 1, 2, 3, 4, 5]

``` python
concat([["abc", "xyz"], ["foo", "bar"]])
```

    ['abc', 'xyz', 'foo', 'bar']

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L638"
target="_blank" style="float:right; font-size:smaller">source</a>

### strcat

``` python

def strcat(
    its, sep:str=''
)->str:

```

*Concatenate stringified items `its`*

``` python
test_eq(strcat(['a',2]), 'a2')
test_eq(strcat(['a',2], ';'), 'a;2')
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L643"
target="_blank" style="float:right; font-size:smaller">source</a>

### detuplify

``` python

def detuplify(
    x
):

```

*If `x` is a tuple with one thing, extract it*

``` python
test_eq(detuplify(()),None)
test_eq(detuplify([1]),1)
test_eq(detuplify([1,2]), [1,2])
test_eq(detuplify(np.array([[1,2]])), np.array([[1,2]]))
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L648"
target="_blank" style="float:right; font-size:smaller">source</a>

### replicate

``` python

def replicate(
    item, match
):

```

*Create tuple of `item` copied `len(match)` times*

``` python
t = [1,1]
test_eq(replicate([1,2], t),([1,2],[1,2]))
test_eq(replicate(1, t),(1,1))
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L653"
target="_blank" style="float:right; font-size:smaller">source</a>

### setify

``` python

def setify(
    o
):

```

*Turn any list like-object into a set.*

``` python
# test
test_eq(setify(None),set())
test_eq(setify('abc'),{'abc'})
test_eq(setify([1,2,2]),{1,2})
test_eq(setify(range(0,3)),{0,1,2})
test_eq(setify({1,2}),{1,2})
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L658"
target="_blank" style="float:right; font-size:smaller">source</a>

### merge

``` python

def merge(
    ds:VAR_POSITIONAL
):

```

*Merge all dictionaries in `ds`*

``` python
test_eq(merge(), {})
test_eq(merge(dict(a=1,b=2)), dict(a=1,b=2))
test_eq(merge(dict(a=1,b=2), dict(b=3,c=4), None), dict(a=1, b=3, c=4))
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L750"
target="_blank" style="float:right; font-size:smaller">source</a>

### range_of

``` python

def range_of(
    x
):

```

*All indices of collection `x` (i.e. `list(range(len(x)))`)*

``` python
test_eq(range_of([1,1,1,1]), [0,1,2,3])
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L674"
target="_blank" style="float:right; font-size:smaller">source</a>

### groupby

``` python

def groupby(
    x, key, val:function=noop
):

```

*Like `itertools.groupby` but doesn’t need to be sorted, and isn’t lazy,
plus some extensions*

``` python
test_eq(groupby('aa ab bb'.split(), itemgetter(0)), {'a':['aa','ab'], 'b':['bb']})
```

You can use an `int` as `key` or `val` (which uses `itemgetter`; passing
a `str` will use `attrgetter`), eg:

``` python
test_eq(groupby('aa ab bb'.split(), 0), {'a':['aa','ab'], 'b':['bb']})
```

…and you can use a tuple as `key` or `val` (which creates a tuple from
the provided keys or vals), eg:

``` python
test_eq(groupby('aaa abc bba'.split(), 0, (1,2)), {'a':[('a','a'),('b','c')], 'b':[('b','a')]})
```

Here’s an example of how to *invert* a grouping, and using a `val`
function:

``` python
d = {0: [1, 3, 7], 2: [3], 3: [5], 4: [8], 5: [4], 7: [5]}
groupby(((o,k) for k,v in d.items() for o in v), 0, 1)
```

    {1: [0], 3: [0, 2], 7: [0], 5: [3, 7], 8: [4], 4: [5]}

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L683"
target="_blank" style="float:right; font-size:smaller">source</a>

### last_index

``` python

def last_index(
    x, o
):

```

*Finds the last index of occurence of `x` in `o` (returns -1 if no
occurence)*

``` python
test_eq(last_index(9, [1, 2, 9, 3, 4, 9, 10]), 5)
test_eq(last_index(6, [1, 2, 9, 3, 4, 9, 10]), -1)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L689"
target="_blank" style="float:right; font-size:smaller">source</a>

### filter_dict

``` python

def filter_dict(
    d, func
):

```

*Filter a `dict` using `func`, applied to keys and values*

``` python
letters = {o:chr(o) for o in range(65,73)}
letters
```

    {65: 'A', 66: 'B', 67: 'C', 68: 'D', 69: 'E', 70: 'F', 71: 'G', 72: 'H'}

``` python
filter_dict(letters, lambda k,v: k<67 or v in 'FG')
```

    {65: 'A', 66: 'B', 70: 'F', 71: 'G'}

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L694"
target="_blank" style="float:right; font-size:smaller">source</a>

### filter_keys

``` python

def filter_keys(
    d, func
):

```

*Filter a `dict` using `func`, applied to keys*

``` python
filter_keys(letters, lt(67))
```

    {65: 'A', 66: 'B'}

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L699"
target="_blank" style="float:right; font-size:smaller">source</a>

### filter_values

``` python

def filter_values(
    d, func
):

```

*Filter a `dict` using `func`, applied to values*

``` python
filter_values(letters, in_('FG'))
```

    {70: 'F', 71: 'G'}

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L704"
target="_blank" style="float:right; font-size:smaller">source</a>

### cycle

``` python

def cycle(
    o
):

```

*Like `itertools.cycle` except creates list of `None`s if `o` is empty*

``` python
test_eq(itertools.islice(cycle([1,2,3]),5), [1,2,3,1,2])
test_eq(itertools.islice(cycle([]),3), [None]*3)
test_eq(itertools.islice(cycle(None),3), [None]*3)
test_eq(itertools.islice(cycle(1),3), [1,1,1])
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L710"
target="_blank" style="float:right; font-size:smaller">source</a>

### zip_cycle

``` python

def zip_cycle(
    x, args:VAR_POSITIONAL
):

```

*Like `itertools.zip_longest` but
[`cycle`](https://fastcore.fast.ai/basics.html#cycle)s through elements
of all but first argument*

``` python
test_eq(zip_cycle([1,2,3,4],list('abc')), [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'a')])
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L715"
target="_blank" style="float:right; font-size:smaller">source</a>

### sorted_ex

``` python

def sorted_ex(
    iterable, key:NoneType=None, reverse:bool=False, cmp:NoneType=None, kwargs:VAR_KEYWORD
):

```

*Like `sorted`, but if key is str use `attrgetter`; if int use
`itemgetter`; use `cmp` comparator function or `key` with `kwargs`*

Attributes can be used for sorting by passing their name as a string:

``` python
class TestObj:
    def __init__(self, x): self.x = x
objs = [TestObj(i) for i in [3,1,2]]
test_eq([o.x for o in sorted_ex(objs, 'x')], [1,2,3])
```

Tuple/list items can be sorted by index position:

``` python
items = [(1,'c'), (2,'b'), (3,'a')]
test_eq(sorted_ex(items, 1), [(3,'a'), (2,'b'), (1,'c')])
```

A custom key function transforms values:

``` python
test_eq(sorted_ex([3,1,2], lambda x: -x), [3,2,1])
```

You can use a comparison function (returning -1/1/0):

``` python
test_eq(sorted_ex([3,1,2], cmp=lambda a,b: 1 if a>b else -1 if a<b else 0), [1,2,3])
```

Additional parameters can be passed to key/cmp functions:

``` python
def key_with_kwargs(x, offset=0): return x + offset
test_eq(sorted_ex([3,1,2], key=key_with_kwargs, offset=10), [1,2,3])
```

Reverse sort capability:

``` python
test_eq(sorted_ex([1,2,3], reverse=True), [3,2,1])
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L727"
target="_blank" style="float:right; font-size:smaller">source</a>

### not\_

``` python

def not_(
    f
):

```

*Create new function that negates result of `f`*

``` python
def f(a): return a>0
test_eq(f(1),True)
test_eq(not_(f)(1),False)
test_eq(not_(f)(a=-1),True)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L733"
target="_blank" style="float:right; font-size:smaller">source</a>

### argwhere

``` python

def argwhere(
    iterable, f, negate:bool=False, kwargs:VAR_KEYWORD
):

```

*Like [`filter_ex`](https://fastcore.fast.ai/basics.html#filter_ex), but
return indices for matching items*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L740"
target="_blank" style="float:right; font-size:smaller">source</a>

### filter_ex

``` python

def filter_ex(
    iterable, f:function=noop, negate:bool=False, gen:bool=False, kwargs:VAR_KEYWORD
):

```

*Like `filter`, but passing `kwargs` to `f`, defaulting `f` to `noop`,
and adding [`negate`](https://fastcore.fast.ai/basics.html#negate) and
[`gen`](https://fastcore.fast.ai/basics.html#gen)*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L750"
target="_blank" style="float:right; font-size:smaller">source</a>

### range_of

``` python

def range_of(
    a, b:NoneType=None, step:NoneType=None
):

```

*All indices of collection `a`, if `a` is a collection, otherwise
`range`*

``` python
test_eq(range_of([1,1,1,1]), [0,1,2,3])
test_eq(range_of(4), [0,1,2,3])
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L756"
target="_blank" style="float:right; font-size:smaller">source</a>

### renumerate

``` python

def renumerate(
    iterable, start:int=0
):

```

*Same as `enumerate`, but returns index as 2nd element instead of 1st*

``` python
test_eq(renumerate('abc'), (('a',0),('b',1),('c',2)))
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L761"
target="_blank" style="float:right; font-size:smaller">source</a>

### first

``` python

def first(
    x, f:NoneType=None, negate:bool=False, kwargs:VAR_KEYWORD
):

```

*First element of `x`, optionally filtered by `f`, or None if missing*

``` python
test_eq(first(['a', 'b', 'c', 'd', 'e']), 'a')
test_eq(first([False]), False)
test_eq(first([False], noop), None)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L768"
target="_blank" style="float:right; font-size:smaller">source</a>

### last

``` python

def last(
    x, f:NoneType=None, negate:bool=False, kwargs:VAR_KEYWORD
):

```

*Last element of `x`, optionally filtered by `f`, or None if missing*

``` python
test_eq(last(['a', 'b', 'c', 'd', 'e']), 'e')
test_eq(last([False]), False)
test_eq(last([False], noop), None)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L776"
target="_blank" style="float:right; font-size:smaller">source</a>

### only

``` python

def only(
    o
):

```

*Return the only item of `o`, raise if `o` doesn’t have exactly one
item*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L786"
target="_blank" style="float:right; font-size:smaller">source</a>

### nested_attr

``` python

def nested_attr(
    o, attr, default:NoneType=None
):

```

*Same as `getattr`, but if `attr` includes a `.`, then looks inside
nested objects*

``` python
class CustomIndexable:
    def __init__(self): self.data = {'a':1,'b':'v','c':{'d':5}}
    def __getitem__(self, key): return self.data[key]

custom_indexable = CustomIndexable()
test_eq(nested_attr(custom_indexable,'a'),1)
test_eq(nested_attr(custom_indexable,'c.d'),5)
test_eq(nested_attr(custom_indexable,'e'),None)
```

class TestObj: def **init**(self): self.nested = {‘key’: \[1, 2,
{‘inner’: ‘value’}\]} test_obj = TestObj()

test_eq(nested_attr(test_obj, ‘nested.key.2.inner’),‘value’)
test_eq(nested_attr(\[1, 2, 3\], ‘1’),2)

``` python
b = {'a':1,'b':'v','c':{'d':5}}
test_eq(nested_attr(b,'b'),'v')
test_eq(nested_attr(b,'c.d'),5)
```

``` python
a = SimpleNamespace(b=(SimpleNamespace(c=1)))
test_eq(nested_attr(a, 'b.c'), getattr(getattr(a, 'b'), 'c'))
test_eq(nested_attr(a, 'b.d'), None)
test_eq(nested_attr(b, 'a'), 1)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L797"
target="_blank" style="float:right; font-size:smaller">source</a>

### nested_setdefault

``` python

def nested_setdefault(
    o, attr, default
):

```

*Same as `setdefault`, but if `attr` includes a `.`, then looks inside
nested objects*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L804"
target="_blank" style="float:right; font-size:smaller">source</a>

### nested_callable

``` python

def nested_callable(
    o, attr
):

```

*Same as
[`nested_attr`](https://fastcore.fast.ai/basics.html#nested_attr) but if
not found will return `noop`*

``` python
a = SimpleNamespace(b=(SimpleNamespace(c=1)))
test_eq(nested_callable(a, 'b.c'), getattr(getattr(a, 'b'), 'c'))
test_eq(nested_callable(a, 'b.d'), noop)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L827"
target="_blank" style="float:right; font-size:smaller">source</a>

### nested_idx

``` python

def nested_idx(
    coll, idxs:VAR_POSITIONAL
):

```

*Index into nested collections, dicts, etc, with `idxs`*

``` python
a = {'b':[1,{'c':2}]}
test_eq(nested_idx(a, 'nope'), None)
test_eq(nested_idx(a, 'nope', 'nup'), None)
test_eq(nested_idx(a, 'b', 3), None)
test_eq(nested_idx(a), a)
test_eq(nested_idx(a, 'b'), [1,{'c':2}])
test_eq(nested_idx(a, 'b', 1), {'c':2})
test_eq(nested_idx(a, 'b', 1, 'c'), 2)
```

``` python
a = SimpleNamespace(b=[1,{'c':2}])
test_eq(nested_idx(a, 'nope'), None)
test_eq(nested_idx(a, 'nope', 'nup'), None)
test_eq(nested_idx(a, 'b', 3), None)
test_eq(nested_idx(a), a)
test_eq(nested_idx(a, 'b'), [1,{'c':2}])
test_eq(nested_idx(a, 'b', 1), {'c':2})
test_eq(nested_idx(a, 'b', 1, 'c'), 2)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L835"
target="_blank" style="float:right; font-size:smaller">source</a>

### set_nested_idx

``` python

def set_nested_idx(
    coll, value, idxs:VAR_POSITIONAL
):

```

*Set value indexed like \`nested_idx*

``` python
set_nested_idx(a, 3, 'b', 0)
test_eq(nested_idx(a, 'b', 0), 3)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L841"
target="_blank" style="float:right; font-size:smaller">source</a>

### val2idx

``` python

def val2idx(
    x
):

```

*Dict from value to index*

``` python
test_eq(val2idx([1,2,3]), {3:2,1:0,2:1})
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L846"
target="_blank" style="float:right; font-size:smaller">source</a>

### uniqueify

``` python

def uniqueify(
    x, sort:bool=False, bidir:bool=False, start:NoneType=None
):

```

*Unique elements in `x`, optional `sort`, optional return reverse
correspondence, optional prepend with elements.*

``` python
t = [1,1,0,5,0,3]
test_eq(uniqueify(t),[1,0,5,3])
test_eq(uniqueify(t, sort=True),[0,1,3,5])
test_eq(uniqueify(t, start=[7,8,6]), [7,8,6,1,0,5,3])
v,o = uniqueify(t, bidir=True)
test_eq(v,[1,0,5,3])
test_eq(o,{1:0, 0: 1, 5: 2, 3: 3})
v,o = uniqueify(t, sort=True, bidir=True)
test_eq(v,[0,1,3,5])
test_eq(o,{0:0, 1: 1, 3: 2, 5: 3})
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L855"
target="_blank" style="float:right; font-size:smaller">source</a>

### loop_first_last

``` python

def loop_first_last(
    values
):

```

*Iterate and generate a tuple with a flag for first and last value.*

``` python
test_eq(loop_first_last(range(3)), [(True,False,0), (False,False,1), (False,True,2)])
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L867"
target="_blank" style="float:right; font-size:smaller">source</a>

### loop_first

``` python

def loop_first(
    values
):

```

*Iterate and generate a tuple with a flag for first value.*

``` python
test_eq(loop_first(range(3)), [(True,0), (False,1), (False,2)])
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L872"
target="_blank" style="float:right; font-size:smaller">source</a>

### loop_last

``` python

def loop_last(
    values
):

```

*Iterate and generate a tuple with a flag for last value.*

``` python
test_eq(loop_last(range(3)), [(False,0), (False,1), (True,2)])
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L877"
target="_blank" style="float:right; font-size:smaller">source</a>

### first_match

``` python

def first_match(
    lst, f, default:NoneType=None
):

```

*First element of `lst` matching predicate `f`, or `default` if none*

``` python
a = [0,2,4,5,6,7,10]
test_eq(first_match(a, lambda o:o%2), 3)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L882"
target="_blank" style="float:right; font-size:smaller">source</a>

### last_match

``` python

def last_match(
    lst, f, default:NoneType=None
):

```

*Last element of `lst` matching predicate `f`, or `default` if none*

``` python
test_eq(last_match(a, lambda o:o%2), 5)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L887"
target="_blank" style="float:right; font-size:smaller">source</a>

### joins

``` python

def joins(
    sep, its
):

```

*Sugar for `sep.join(map(str, its))`*

``` python
# Gives: `TypeError: sequence item 0: expected str…`:
#   ",".join([1,2,3])
joins(",", [1,2,3])
```

    '1,2,3'

## fastuple

A tuple with extended functionality.

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L906"
target="_blank" style="float:right; font-size:smaller">source</a>

#### fastuple

``` python

def fastuple(
    args:VAR_POSITIONAL, kwargs:VAR_KEYWORD
):

```

*A `tuple` with elementwise ops and more friendly **init** behavior*

#### Friendly init behavior

Common failure modes when trying to initialize a tuple in python:

``` py
tuple(3)
> TypeError: 'int' object is not iterable
```

or

``` py
tuple(3, 4)
> TypeError: tuple expected at most 1 arguments, got 2
```

However, [`fastuple`](https://fastcore.fast.ai/basics.html#fastuple)
allows you to define tuples like this and in the usual way:

``` python
test_eq(fastuple(3), (3,))
test_eq(fastuple(3,4), (3, 4))
test_eq(fastuple((3,4)), (3, 4))
```

#### Elementwise operations

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L925"
target="_blank" style="float:right; font-size:smaller">source</a>

##### fastuple.add

``` python

def add(
    args:VAR_POSITIONAL
):

```

*`+` is already defined in `tuple` for concat, so use `add` instead*

``` python
test_eq(fastuple.add((1,1),(2,2)), (3,3))
test_eq_type(fastuple(1,1).add(2), fastuple(3,3))
test_eq(fastuple('1','2').add('2'), fastuple('12','22'))
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L921"
target="_blank" style="float:right; font-size:smaller">source</a>

##### fastuple.mul

``` python

def mul(
    args:VAR_POSITIONAL
):

```

*`*` is already defined in `tuple` for replicating, so use `mul`
instead*

``` python
test_eq_type(fastuple(1,1).mul(2), fastuple(2,2))
```

#### Other Elementwise Operations

Additionally, the following elementwise operations are available: -
`le`: less than or equal - `eq`: equal - `gt`: greater than - `min`:
minimum of

``` python
test_eq(fastuple(3,1).le(1), (False, True))
test_eq(fastuple(3,1).eq(1), (False, True))
test_eq(fastuple(3,1).gt(1), (True, False))
test_eq(fastuple(3,1).min(2), (2,1))
```

You can also do other elementwise operations like negate a
[`fastuple`](https://fastcore.fast.ai/basics.html#fastuple), or subtract
two [`fastuple`](https://fastcore.fast.ai/basics.html#fastuple)s:

``` python
test_eq(-fastuple(1,2), (-1,-2))
test_eq(~fastuple(1,0,1), (False,True,False))

test_eq(fastuple(1,1)-fastuple(2,2), (-1,-1))
```

``` python
test_eq(type(fastuple(1)), fastuple)
test_eq_type(fastuple(1,2), fastuple(1,2))
test_ne(fastuple(1,2), fastuple(1,3))
test_eq(fastuple(), ())
```

## Functions on Functions

Utilities for functional programming or for defining, modifying, or
debugging functions.

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L952"
target="_blank" style="float:right; font-size:smaller">source</a>

### bind

``` python

def bind(
    func, pargs:VAR_POSITIONAL, pkwargs:VAR_KEYWORD
):

```

*Same as `partial`, except you can use `arg0` `arg1` etc param
placeholders*

[`bind`](https://fastcore.fast.ai/basics.html#bind) is the same as
`partial`, but also allows you to reorder positional arguments using
variable name(s) `arg{i}` where i refers to the zero-indexed positional
argument. [`bind`](https://fastcore.fast.ai/basics.html#bind) as
implemented currently only supports reordering of up to the first 5
positional arguments.

Consider the function `myfunc` below, which has 3 positional arguments.
These arguments can be referenced as `arg0`, `arg1`, and `arg1`,
respectively.

``` python
def myfn(a,b,c,d=1,e=2): return(a,b,c,d,e)
```

In the below example we bind the positional arguments of `myfn` as
follows:

- The second input `14`, referenced by `arg1`, is substituted for the
  first positional argument.
- We supply a default value of `17` for the second positional argument.
- The first input `19`, referenced by `arg0`, is subsituted for the
  third positional argument.

``` python
test_eq(bind(myfn, arg1, 17, arg0, e=3)(19,14), (14,17,19,1,3))
```

In this next example:

- We set the default value to `17` for the first positional argument.
- The first input `19` refrenced by `arg0`, becomes the second
  positional argument.
- The second input `14` becomes the third positional argument.
- We override the default the value for named argument `e` to `3`.

``` python
test_eq(bind(myfn, 17, arg0, e=3)(19,14), (17,19,14,1,3))
```

This is an example of using
[`bind`](https://fastcore.fast.ai/basics.html#bind) like `partial` and
do not reorder any arguments:

``` python
test_eq(bind(myfn)(17,19,14), (17,19,14,1,2))
```

[`bind`](https://fastcore.fast.ai/basics.html#bind) can also be used to
change default values. In the below example, we use the first input `3`
to override the default value of the named argument `e`, and supply
default values for the first three positional arguments:

``` python
test_eq(bind(myfn, 17,19,14,e=arg0)(3), (17,19,14,1,3))
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L967"
target="_blank" style="float:right; font-size:smaller">source</a>

### mapt

``` python

def mapt(
    func, iterables:VAR_POSITIONAL
):

```

*Tuplified `map`*

``` python
t = [0,1,2,3]
test_eq(mapt(operator.neg, t), (0,-1,-2,-3))
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L972"
target="_blank" style="float:right; font-size:smaller">source</a>

### map_ex

``` python

def map_ex(
    iterable, f, args:VAR_POSITIONAL, gen:bool=False, kwargs:VAR_KEYWORD
):

```

*Like `map`, but use
[`bind`](https://fastcore.fast.ai/basics.html#bind), and supports `str`
and indexing*

``` python
test_eq(map_ex(t,operator.neg), [0,-1,-2,-3])
```

If `f` is a string then it is treated as a format string to create the
mapping:

``` python
test_eq(map_ex(t, '#{}#'), ['#0#','#1#','#2#','#3#'])
```

If `f` is a dictionary (or anything supporting `__getitem__`) then it is
indexed to create the mapping:

``` python
test_eq(map_ex(t, list('abcd')), list('abcd'))
```

You can also pass the same `arg` params that
[`bind`](https://fastcore.fast.ai/basics.html#bind) accepts:

``` python
def f(a=None,b=None): return b
test_eq(map_ex(t, f, b=arg0), range(4))
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L982"
target="_blank" style="float:right; font-size:smaller">source</a>

### compose

``` python

def compose(
    funcs:VAR_POSITIONAL, order:NoneType=None
):

```

*Create a function that composes all functions in `funcs`, passing along
remaining `*args` and `**kwargs` to all*

``` python
f1 = lambda o,p=0: (o*2)+p
f2 = lambda o,p=1: (o+1)/p
test_eq(f2(f1(3)), compose(f1,f2)(3))
test_eq(f2(f1(3,p=3),p=3), compose(f1,f2)(3,p=3))
test_eq(f2(f1(3,  3),  3), compose(f1,f2)(3,  3))

f1.order = 1
test_eq(f1(f2(3)), compose(f1,f2, order="order")(3))
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L994"
target="_blank" style="float:right; font-size:smaller">source</a>

### maps

``` python

def maps(
    args:VAR_POSITIONAL, retain:function=noop
):

```

*Like `map`, except funcs are composed first*

``` python
test_eq(maps([1]), [1])
test_eq(maps(operator.neg, [1,2]), [-1,-2])
test_eq(maps(operator.neg, operator.neg, [1,2]), [1,2])
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1001"
target="_blank" style="float:right; font-size:smaller">source</a>

### partialler

``` python

def partialler(
    f, args:VAR_POSITIONAL, order:NoneType=None, kwargs:VAR_KEYWORD
):

```

*Like `functools.partial` but also copies over docstring*

``` python
def _f(x,a=1):
    "test func"
    return x-a
_f.order=1

f = partialler(_f, 2)
test_eq(f.order, 1)
test_eq(f(3), -1)
f = partialler(_f, a=2, order=3)
test_eq(f.__doc__, "test func")
test_eq(f.order, 3)
test_eq(f(3), _f(3,2))
```

``` python
class partial0:
    "Like `partialler`, but args passed to callable are inserted at started, instead of at end"
    def __init__(self, f, *args, order=None, **kwargs):
        self.f,self.args,self.kwargs = f,args,kwargs
        self.order = ifnone(order, getattr(f,'order',None))
        self.__doc__ = f.__doc__

    def __call__(self, *args, **kwargs): return self.f(*args, *self.args, **kwargs, **self.kwargs)
```

``` python
f = partial0(_f, 2)
test_eq(f.order, 1)
test_eq(f(3), 1) # NB: different to `partialler` example
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1010"
target="_blank" style="float:right; font-size:smaller">source</a>

### instantiate

``` python

def instantiate(
    t
):

```

*Instantiate `t` if it’s a type, otherwise do nothing*

``` python
test_eq_type(instantiate(int), 0)
test_eq_type(instantiate(1), 1)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1018"
target="_blank" style="float:right; font-size:smaller">source</a>

### using_attr

``` python

def using_attr(
    f, attr
):

```

*Construct a function which applies `f` to the argument’s attribute
`attr`*

``` python
t = Path('/a/b.txt')
f = using_attr(str.upper, 'name')
test_eq(f(t), 'B.TXT')
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1023"
target="_blank" style="float:right; font-size:smaller">source</a>

### negate

``` python

def negate(
    f
):

```

*Returns the negation of `f`*

``` python
def true():
    'Returns True'
    return True
```

``` python
false = negate(true)
print(false.__doc__)
test_eq(false(), not true())
```

    Returns `not true(...)`

    Original: Returns True

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1031"
target="_blank" style="float:right; font-size:smaller">source</a>

### spread

``` python

def spread(
    f
):

```

*Wrap `f` to accept a single iterable and spread it as positional args*

[`spread`](https://fastcore.fast.ai/basics.html#spread) wraps a function
so it accepts a single iterable (like a tuple or list) and unpacks it as
positional arguments.

It can be used to replicate `itertools.starmap`:

``` python
def add(a, b): return a + b
pairs = [(1,2), (3,4), (5,6)]
list(map(spread(add), pairs))  # [3, 7, 11]
```

    [3, 7, 11]

It can also be used to create `star` versions of functions such as
`filter`, which aren’t otherwise in the stdlib:

``` python
def is_long_segment(x1, y1, x2, y2, maxlen=4): return ((x2-x1)**2 + (y2-y1)**2)**0.5 > maxlen

segments = [(0,0,2,3), (1,1,4,5), (0,0,6,8)]
list(filter(spread(is_long_segment), segments))
```

    [(1, 1, 4, 5), (0, 0, 6, 8)]

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1038"
target="_blank" style="float:right; font-size:smaller">source</a>

### dspread

``` python

def dspread(
    f
):

```

*Wrap `f` to accept a single dict and spread it as keyword args*

[`dspread`](https://fastcore.fast.ai/basics.html#dspread) is the
dictionary equivalent of
[`spread`](https://fastcore.fast.ai/basics.html#spread) - it wraps a
function to accept a single dictionary and unpacks it as keyword
arguments. For instance:

``` python
def greet(name, greeting='Hello'): return f'{greeting}, {name}!'
configs = [{'name': 'Alice'}, {'name': 'Bob', 'greeting': 'Hi'}]
list(map(dspread(greet), configs))  # ['Hello, Alice!', 'Hi, Bob!']
```

    ['Hello, Alice!', 'Hi, Bob!']

A more realistic example showing API request configuration. Each request
dictionary may have different keys present, and
[`dspread`](https://fastcore.fast.ai/basics.html#dspread) handles this
naturally (missing keys use the function’s defaults):

``` python
def api_request(endpoint, method='GET', timeout=30, headers=None):
    return f"{method} {endpoint} (timeout={timeout})"

requests = [
    {'endpoint': '/users', 'method': 'POST', 'timeout': 60},
    {'endpoint': '/data'},
    {'endpoint': '/health', 'method': 'HEAD', 'timeout': 5}
]
list(map(dspread(api_request), requests))
```

    ['POST /users (timeout=60)',
     'GET /data (timeout=30)',
     'HEAD /health (timeout=5)']

### Self (with an *uppercase* S)

A Concise Way To Create Lambdas

This is a concise way to create lambdas that are calling methods on an
object (note the capitalization!)

`Self.sum()`, for instance, is a shortcut for `lambda o: o.sum()`.

``` python
f = Self.sum()
x = np.array([3.,1])
test_eq(f(x), 4.)

# This is equivalent to above
f = lambda o: o.sum()
x = np.array([3.,1])
test_eq(f(x), 4.)

f = Self.argmin()
arr = np.array([1,2,3,4,5])
test_eq(f(arr), arr.argmin())

f = Self.sum().is_integer()
x = np.array([3.,1])
test_eq(f(x), True)

f = Self.sum().real.is_integer()
x = np.array([3.,1])
test_eq(f(x), True)

f = Self.imag()
test_eq(f(3), 0)

f = Self[1]
test_eq(f(x), 1)
```

`Self` is also callable, which creates a function which calls any
function passed to it, using the arguments passed to `Self`:

``` python
def f(a, b=3): return a+b+2
def g(a, b=3): return a*b
fg = Self(1,b=2)
list(map(fg, [f,g]))
```

    [5, 2]

## Patching

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1088"
target="_blank" style="float:right; font-size:smaller">source</a>

### copy_func

``` python

def copy_func(
    f
):

```

*Copy a non-builtin function (NB `copy.copy` does not work for this)*

Sometimes it may be desirable to make a copy of a function that doesn’t
point to the original object. When you use Python’s built in `copy.copy`
or `copy.deepcopy` to copy a function, you get a reference to the
original object:

``` python
import copy as cp
```

``` python
def foo(): pass
a = cp.copy(foo)
b = cp.deepcopy(foo)

a.someattr = 'hello' # since a and b point at the same object, updating a will update b
test_eq(b.someattr, 'hello')

assert a is foo and b is foo
```

However, with
[`copy_func`](https://fastcore.fast.ai/basics.html#copy_func), you can
retrieve a copy of a function without a reference to the original
object:

``` python
c = copy_func(foo) # c is an indpendent object
assert c is not foo
```

``` python
def g(x, *, y=3): return x+y
test_eq(copy_func(g)(4), 7)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1104"
target="_blank" style="float:right; font-size:smaller">source</a>

### patch_to

``` python

def patch_to(
    cls, as_prop:bool=False, cls_method:bool=False, set_prop:bool=False, static_method:bool=False, nm:NoneType=None,
    glb:NoneType=None
):

```

*Decorator: add `f` to `cls`*

The `@patch_to` decorator allows you to [monkey
patch](https://stackoverflow.com/questions/5626193/what-is-monkey-patching)
a function into a class as a method:

``` python
class _T3(int): pass  

@patch_to(_T3)
def func1(self, a): return self+a

t = _T3(1) # we initialized `t` to a type int = 1
test_eq(t.func1(2), 3) # we add 2 to `t`, so 2 + 1 = 3

if sys.version_info >= (3,11):
    test_eq(_T3.func1.__code__.co_qualname, '_T3.func1')
```

You can access instance properties in the usual way via `self`:

``` python
class _T4():
    def __init__(self, g): self.g = g
        
@patch_to(_T4)
def greet(self, x): return self.g + x
        
t = _T4('hello ') # this sets self.g = 'hello '
test_eq(t.greet('world'), 'hello world') #t.greet('world') will append 'world' to 'hello '
```

You can instead specify that the method should be a class method by
setting `cls_method=True`:

``` python
class _T5(int): attr = 3 # attr is a class attribute we will access in a later method
    
@patch_to(_T5, cls_method=True)
def func(cls, x): return cls.attr + x # you can access class attributes in the normal way

test_eq(_T5.func(4), 7)
```

Additionally you can specify that the function you want to patch should
be a class attribute with `as_prop=True`:

``` python
@patch_to(_T5, as_prop=True)
def add_ten(self): return self + 10

t = _T5(4)
test_eq(t.add_ten, 14)
```

Once you have a property, you can assign a setter with `set_prop=True`:

``` python
class _T2():
    def __init__(self, val): self._val = val

@patch_to(_T2, as_prop=True)
def val(self): return self._val

t = _T2(2)
test_eq(t.val, 2)

@patch_to(_T2, set_prop=True)
def val(self, val): self._val = val

t.val = 3
test_eq(t.val, 3)
```

Instead of passing one class to the `@patch_to` decorator, you can pass
multiple classes in a tuple to simulteanously patch more than one class
with the same method:

``` python
class _T6(int): pass
class _T7(int): pass

@patch_to((_T6,_T7))
def func_mult(self, a): return self*a

t = _T6(2)
test_eq(t.func_mult(4), 8)
t = _T7(2)
test_eq(t.func_mult(4), 8)
```

You can also rename the function in the patched class:

``` python
class _T8(int): pass  

@patch_to(_T8, nm='add_value')
def func2(self, a): return self+a

t = _T8(1)
test_eq(t.add_value(2), 3)
test_eq(_T8.add_value.__name__, 'add_value')
assert not hasattr(t, 'func2')
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1127"
target="_blank" style="float:right; font-size:smaller">source</a>

### patch

``` python

def patch(
    f:NoneType=None, as_prop:bool=False, cls_method:bool=False, static_method:bool=False, set_prop:bool=False,
    nm:NoneType=None
):

```

*Decorator: add `f` to the first parameter’s class (based on f’s type
annotations)*

`@patch` is an alternative to `@patch_to` that allows you similarly
monkey patch class(es) by using [type
annotations](https://docs.python.org/3/library/typing.html):

``` python
class _T8(int): pass  

@patch
def func(self:_T8, a): return self+a

t = _T8(1)  # we initilized `t` to a type int = 1
test_eq(t.func(3), 4) # we add 3 to `t`, so 3 + 1 = 4
test_eq(t.func.__qualname__, '_T8.func')
if sys.version_info >= (3,11):
    test_eq(_T8.func.__code__.co_qualname, '_T8.func')
```

``` python
class MyMath: pass

@patch_to(MyMath, static_method=True)
def add(a, b): return a + b

@patch(static_method=True)
def mul(a:MyMath, b): return a * b

test_eq(MyMath.add(2, 3), 5)
test_eq(MyMath.mul(2, 3), 6)
```

Similarly to
[`patch_to`](https://fastcore.fast.ai/basics.html#patch_to), you can
supply a union of classes instead of a single class in your type
annotations to patch multiple classes:

``` python
class _T9(int): pass 

@patch
def func2(x:_T8|_T9, a): return x*a # will patch both _T8 and _T9

t = _T8(2)
test_eq(t.func2(4), 8)
test_eq(t.func2.__qualname__, '_T8.func2')

t = _T9(2)
test_eq(t.func2(4), 8)
test_eq(t.func2.__qualname__, '_T9.func2')
```

Just like [`patch_to`](https://fastcore.fast.ai/basics.html#patch_to)
decorator you can use `as_prop`, `set_prop`, and `cls_method` parameters
with [`patch`](https://fastcore.fast.ai/basics.html#patch) decorator:

``` python
@patch(as_prop=True)
def add_ten(self:_T5): return self + 10

t = _T5(4)
test_eq(t.add_ten, 14)
```

``` python
class _T2():
    def __init__(self, val): self._val = val

@patch(as_prop=True)
def val(self:_T2): return self._val

t = _T2(2)
test_eq(t.val, 2)

@patch(set_prop=True)
def val(self:_T2, val): self._val = val

t.val = 3
test_eq(t.val, 3)
```

``` python
class _T5(int): attr = 3 # attr is a class attribute we will access in a later method
    
@patch(cls_method=True)
def func(cls:_T5, x): return cls.attr + x # you can access class attributes in the normal way

test_eq(_T5.func(4), 7)
```

``` python
class _T8(int): pass  

@patch(nm='add_value')
def func2(self:_T8, a): return self+a

t = _T8(1)
test_eq(t.add_value(2), 3)
test_eq(_T8.add_value.__name__, 'add_value')
assert not hasattr(t, 'func2')
```

Patching `classmethod` shouldn’t affect how python’s inheritance works

``` python
class FastParent: pass

@patch(cls_method=True)
def type_cls(cls: FastParent): return cls

class FastChild(FastParent): pass

parent = FastParent()
test_eq(parent.type_cls(), FastParent)

child = FastChild()
test_eq(child.type_cls(), FastChild)
```

## Other Helpers

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1142"
target="_blank" style="float:right; font-size:smaller">source</a>

### extend_enum

``` python

def extend_enum(
    cls, # Enum class to modify
    n, # Name of the new enum member
    v, # Value of the new enum member
):

```

*Add new member `n` with value `v` to enum class `cls` at runtime*

[`extend_enum`](https://fastcore.fast.ai/basics.html#extend_enum)
mutates an existing enum class by constructing a new member, registering
it in the enum’s internal lookup tables, and attaching it as a class
attribute, so it behaves like a normal enum member created in the
original class definition.

``` python
from enum import Enum
```

``` python
class Color(Enum): red = 1; blue = 2

extend_enum(Color, 'green', 3)
Color.green, Color['green'], Color(3)
```

    (<Color.green: 3>, <Color.green: 3>, <Color.green: 3>)

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1159"
target="_blank" style="float:right; font-size:smaller">source</a>

### compile_re

``` python

def compile_re(
    pat
):

```

*Compile `pat` if it’s not None*

``` python
assert compile_re(None) is None
assert compile_re('a').match('ab')
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1164"
target="_blank" style="float:right; font-size:smaller">source</a>

#### ImportEnum

``` python

def ImportEnum(
    args:VAR_POSITIONAL, kwds:VAR_KEYWORD
):

```

*An `Enum` that can have its values imported*

``` python
_T = ImportEnum('_T', {'foobar':1, 'goobar':2})
_T.imports()
test_eq(foobar, _T.foobar)
test_eq(goobar, _T.goobar)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1172"
target="_blank" style="float:right; font-size:smaller">source</a>

#### StrEnum

``` python

def StrEnum(
    args:VAR_POSITIONAL, kwds:VAR_KEYWORD
):

```

*An [`ImportEnum`](https://fastcore.fast.ai/basics.html#importenum) that
behaves like a `str`*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1177"
target="_blank" style="float:right; font-size:smaller">source</a>

### str_enum

``` python

def str_enum(
    name, vals:VAR_POSITIONAL
):

```

*Simplified creation of
[`StrEnum`](https://fastcore.fast.ai/basics.html#strenum) types*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1182"
target="_blank" style="float:right; font-size:smaller">source</a>

#### ValEnum

``` python

def ValEnum(
    args:VAR_POSITIONAL, kwds:VAR_KEYWORD
):

```

*An [`ImportEnum`](https://fastcore.fast.ai/basics.html#importenum) that
stringifies using values*

``` python
_T = str_enum('_T', 'a', 'b')
test_eq(f'{_T.a}', 'a')
test_eq(_T.a, 'a')
test_eq(list(_T.__members__), ['a','b'])
print(_T.a, _T.a.upper())
```

    a A

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1187"
target="_blank" style="float:right; font-size:smaller">source</a>

#### Stateful

``` python

def Stateful(
    args:VAR_POSITIONAL, kwargs:VAR_KEYWORD
):

```

*A base class/mixin for objects that should not serialize all their
state*

``` python
class _T(Stateful):
    def __init__(self):
        super().__init__()
        self.a=1
        self._state['test']=2

t = _T()
t2 = pickle.loads(pickle.dumps(t))
test_eq(t.a,1)
test_eq(t._state['test'],2)
test_eq(t2.a,1)
test_eq(t2._state,{})
```

Override `_init_state` to do any necessary setup steps that are required
during `__init__` or during deserialization (e.g. `pickle.load`). Here’s
an example of how
[`Stateful`](https://fastcore.fast.ai/basics.html#stateful) simplifies
the official Python example for [Handling Stateful
Objects](https://docs.python.org/3/library/pickle.html#handling-stateful-objects).

``` python
class TextReader(Stateful):
    """Print and number lines in a text file."""
    _stateattrs=('file',)
    def __init__(self, filename):
        self.filename,self.lineno = filename,0
        super().__init__()

    def readline(self):
        self.lineno += 1
        line = self.file.readline()
        if line: return f"{self.lineno}: {line.strip()}"

    def _init_state(self):
        self.file = open(self.filename)
        for _ in range(self.lineno): self.file.readline()
```

``` python
reader = TextReader("00_test.ipynb")
print(reader.readline())
print(reader.readline())

new_reader = pickle.loads(pickle.dumps(reader))
print(reader.readline())
```

    1: {
    2: "cells": [
    3: {

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1207"
target="_blank" style="float:right; font-size:smaller">source</a>

### NotStr

``` python

def NotStr(
    s
):

```

*Behaves like a `str`, but isn’t an instance of one*

``` python
s = NotStr("hello")
assert not isinstance(s, str)
test_eq(s, 'hello')
test_eq(s*2, 'hellohello')
test_eq(len(s), 5)
test_eq(s[:2], "he")
test_eq(s[2], "l")
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1225"
target="_blank" style="float:right; font-size:smaller">source</a>

#### PrettyString

``` python

def PrettyString(
    args:VAR_POSITIONAL, kwargs:VAR_KEYWORD
):

```

*Little hack to get strings to show properly in Jupyter.*

Allow strings with special characters to render properly in Jupyter.
Without calling `print()` strings with special characters are displayed
like so:

``` python
with_special_chars='a string\nwith\nnew\nlines and\ttabs'
with_special_chars
```

    'a string\nwith\nnew\nlines and\ttabs'

We can correct this with
[`PrettyString`](https://fastcore.fast.ai/basics.html#prettystring):

``` python
PrettyString(with_special_chars)
```

    a string
    with
    new
    lines and   tabs

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1230"
target="_blank" style="float:right; font-size:smaller">source</a>

### even_mults

``` python

def even_mults(
    start, stop, n
):

```

*Build log-stepped array from `start` to
[`stop`](https://fastcore.fast.ai/basics.html#stop) in `n` steps.*

``` python
test_eq(even_mults(2,8,3), [2,4,8])
test_eq(even_mults(2,32,5), [2,4,8,16,32])
test_eq(even_mults(2,8,1), 8)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1238"
target="_blank" style="float:right; font-size:smaller">source</a>

### num_cpus

``` python

def num_cpus(
    
):

```

*Get number of cpus*

``` python
num_cpus()
```

    16

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1246"
target="_blank" style="float:right; font-size:smaller">source</a>

### add_props

``` python

def add_props(
    f, g:NoneType=None, n:int=2
):

```

*Create properties passing each of `range(n)` to f*

``` python
class _T(): a,b = add_props(lambda i,x:i*2)

t = _T()
test_eq(t.a,0)
test_eq(t.b,2)
```

``` python
class _T(): 
    def __init__(self, v): self.v=v
    def _set(i, self, v): self.v[i] = v
    a,b = add_props(lambda i,x: x.v[i], _set)

t = _T([0,2])
test_eq(t.a,0)
test_eq(t.b,2)
t.a = t.a+1
t.b = 3
test_eq(t.a,1)
test_eq(t.b,3)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1255"
target="_blank" style="float:right; font-size:smaller">source</a>

### str2bool

``` python

def str2bool(
    s
):

```

*Case-insensitive convert string `s` too a bool
(`y`,`yes`,`t`,[`true`](https://fastcore.fast.ai/basics.html#true),`on`,`1`-\>`True`)*

True values are ‘y’, ‘yes’, ‘t’, ‘true’, ‘on’, and ‘1’; false values are
‘n’, ‘no’, ‘f’, ‘false’, ‘off’, and ‘0’. Raises `ValueError` if ‘val’ is
anything else.

``` python
for o in "y YES t True on 1".split(): assert str2bool(o)
for o in "n no FALSE off 0".split(): assert not str2bool(o)
for o in 0,None,'',False: assert not str2bool(o)
for o in 1,True: assert str2bool(o)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1265"
target="_blank" style="float:right; font-size:smaller">source</a>

### str2int

``` python

def str2int(
    s
)->int:

```

*Convert `s` to an `int`*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1274"
target="_blank" style="float:right; font-size:smaller">source</a>

### str2float

``` python

def str2float(
    s:str
):

```

*Convert `s` to a float*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1281"
target="_blank" style="float:right; font-size:smaller">source</a>

### str2list

``` python

def str2list(
    s:str
):

```

*Convert `s` to a list*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1290"
target="_blank" style="float:right; font-size:smaller">source</a>

### str2date

``` python

def str2date(
    s:str
)->date:

```

*`date.fromisoformat` with empty string handling*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1299"
target="_blank" style="float:right; font-size:smaller">source</a>

### to_date

``` python

def to_date(
    arg
):

```

*Call self as a function.*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1298"
target="_blank" style="float:right; font-size:smaller">source</a>

### to_list

``` python

def to_list(
    arg
):

```

*Call self as a function.*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1297"
target="_blank" style="float:right; font-size:smaller">source</a>

### to_float

``` python

def to_float(
    arg
):

```

*Call self as a function.*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1296"
target="_blank" style="float:right; font-size:smaller">source</a>

### to_int

``` python

def to_int(
    arg
):

```

*Call self as a function.*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1295"
target="_blank" style="float:right; font-size:smaller">source</a>

### to_bool

``` python

def to_bool(
    arg
):

```

*Call self as a function.*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1306"
target="_blank" style="float:right; font-size:smaller">source</a>

### typed

``` python

def typed(
    _func:NoneType=None, cast:bool=False
):

```

*Decorator to check param and return types at runtime, with optional
casting*

[`typed`](https://fastcore.fast.ai/basics.html#typed) validates argument
types at **runtime**. This is in contrast to
[MyPy](http://mypy-lang.org/) which only offers static type checking.

For example, a `TypeError` will be raised if we try to pass an integer
into the first argument of the below function:

``` python
@typed
def discount(price:int, pct:float) -> float:
    return (1-pct) * price

with ExceptionExpected(TypeError): discount(100.0, .1)
```

You can have automatic casting based on heuristics by specifying
`typed(cast=True)`. If casting is not possible, a `TypeError` is raised.

``` python
@typed(cast=True)
def discount(price:int, pct:float) -> float:
    return (1-pct) * price

assert 90.0 == discount(100.5, .1) # will auto cast 100.5 to the int 100
assert 90.0 == discount(' 100 ', .1) # will auto cast the str "100" to the int 100
with ExceptionExpected(TypeError): discount("a", .1)
```

We can also optionally allow multiple types by enumarating the types in
a tuple as illustrated below:

``` python
@typed
def discount(price:int|float, pct:float): 
    return (1-pct) * price

assert 90.0 == discount(100.0, .1)

@typed(cast=True)
def discount(price:int|None, pct:float):
    return (1-pct) * price

assert 90.0 == discount(100.0, .1)
```

We currently do not support union types when casting.

``` python
@typed(cast=True)
def discount(price:int|float, pct:float):
    return (1-pct) * price

with ExceptionExpected(AssertionError): assert 90.0 == discount("100.0", .1)
```

[`typed`](https://fastcore.fast.ai/basics.html#typed) works with
classes, too:

``` python
class Foo:
    @typed
    def __init__(self, a:int, b: int, c:str): pass
    @typed(cast=True)
    def test(cls, d:str): return d

with ExceptionExpected(TypeError): Foo(1, 2, 3) 
assert isinstance(Foo(1,2, 'a string').test(10), str)
```

It also works with custom types.

``` python
@typed
def test_foo(foo: Foo): pass

with ExceptionExpected(TypeError): test_foo(1)
test_foo(Foo(1, 2, 'a string'))
```

``` python
class Bar:
    @typed
    def __init__(self, a:int): self.a = a
@typed(cast=True)
def test_bar(bar: Bar): return bar

assert isinstance(test_bar(1), Bar)
test_eq(test_bar(1).a, 1)
with ExceptionExpected(TypeError): test_bar("foobar")
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1341"
target="_blank" style="float:right; font-size:smaller">source</a>

### exec_new

``` python

def exec_new(
    code
):

```

*Execute `code` in a new environment and return it*

``` python
g = exec_new('a=1')
test_eq(g['a'], 1)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1349"
target="_blank" style="float:right; font-size:smaller">source</a>

### exec_import

``` python

def exec_import(
    mod, sym
):

```

*Import `sym` from `mod` in a new environment*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1355"
target="_blank" style="float:right; font-size:smaller">source</a>

### sig_with_params

``` python

def sig_with_params(
    sig, remove:NoneType=None, keep:NoneType=None, updates:VAR_KEYWORD
):

```

*Call self as a function.*

[`sig_with_params`](https://fastcore.fast.ai/basics.html#sig_with_params)
lets you modify a function signature by adding, replacing, or removing
parameters. This is useful when creating wrapper functions or decorators
that need to adjust the signature of the wrapped function.

You can remove parameters by name:

``` python
from inspect import signature, Parameter
```

``` python
def foo(a, b, c=3): pass
sig = signature(foo)

new_sig = sig_with_params(sig, remove=['b'])
test_eq(list(new_sig.parameters.keys()), ['a', 'c'])
```

You can also add new parameters:

``` python
new_param = Parameter('d', Parameter.KEYWORD_ONLY, default=4)
new_sig = sig_with_params(sig, d=new_param)
test_eq(list(new_sig.parameters.keys()), ['a', 'b', 'c', 'd'])
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/basics.py#L1364"
target="_blank" style="float:right; font-size:smaller">source</a>

### fdelegates

``` python

def fdelegates(
    to
):

```

*Call self as a function.*

This is a simplified version of
[`fastcore.meta.delegates`](https://fastcore.fast.ai/meta.html#delegates)
that supports only regular functions.

## Notebook functions

------------------------------------------------------------------------

### ipython_shell

``` python

def ipython_shell(
    
):

```

*Same as `get_ipython` but returns `False` if not in IPython*

------------------------------------------------------------------------

### in_ipython

``` python

def in_ipython(
    
):

```

*Check if code is running in some kind of IPython environment*

------------------------------------------------------------------------

### in_colab

``` python

def in_colab(
    
):

```

*Check if the code is running in Google Colaboratory*

------------------------------------------------------------------------

### in_jupyter

``` python

def in_jupyter(
    
):

```

*Check if the code is running in a jupyter notebook*

------------------------------------------------------------------------

### in_notebook

``` python

def in_notebook(
    
):

```

*Check if the code is running in a jupyter notebook*

These variables are available as booleans in `fastcore.basics` as
`IN_IPYTHON`, `IN_JUPYTER`, `IN_COLAB` and `IN_NOTEBOOK`.

``` python
IN_IPYTHON, IN_JUPYTER, IN_COLAB, IN_NOTEBOOK
```

    (True, True, False, True)
