# Python : Core : Types - [reference/datamodel](https://docs.python.org/3/reference/datamodel.html) - [library/stdtypes](https://docs.python.org/3/library/stdtypes.html) - [library/collections](https://docs.python.org/3/library/collections.html) - [library/collections.abc](https://docs.python.org/3/library/collections.abc.html) - [library/decimal](https://docs.python.org/3/library/decimal.html) - [library/enum](https://docs.python.org/3/library/enum.html) - [library/numbers](https://docs.python.org/3/library/numbers.html) - [library/uuid](https://docs.python.org/3/library/uuid.html) ## Basics The principal built-in types are *numerics*, *sequences*, *mappings*, *classes*, *instances* and *exceptions*. (Strings are sequences.) Everything is an object with a type (returned by `type()`), a value, and a constant identity (returned by `id()` and compared with `is`). Some objects are "containers", which contain references to other objects. #### Constructors ```python # Built-in bool(), bytearrays(), bytes(), complex(), dict(), float(), frozenset(), int(), list(), range(), set(), slice(), str(), tuple() # Standard Library datetime : date(), datetime(), time() decimal : Decimal() enum : Enum() uuid : UUID() ``` #### Special Values - `None` is both a type and a value. - `NotImplemented` is both a type and a value. *(Numeric methods and rich comparison methods should return this value if they do not implement the operation for the operands provided.)* - `...` is the literal for the `Ellipsis` value, which is the only instance of `types.EllipsisType` #### Numbers ###### Booleans A subclass of `int` with instances `True` and `False`, which evaluate to `1` and `0` in numeric contexts. ###### Truthiness By default, an object is considered true unless its class defines either: - a `__bool__()` method that returns `False` - a `__len__()` method that returns `0` > [!info] Falsy Values > ```python > False, None, 0, 0.0, "", [], (), {}, set(), range(0) > ``` ###### Ints & Floats ```python # turn floats into ints math.trunc( x ) math.floor( x ) math.ceil( x ) int.bit_length() # min necessary to represent value int.bit_count() # count of 1s int.to_bytes( ... ) # https://docs.python.org/3/library/stdtypes.html#int.to_bytes int.from_bytes( ... ) # https://docs.python.org/3/library/stdtypes.html#int.from_bytes int.is_integer() float.is_integer() ``` ###### Decimals ```python Decimal( 0.1 ) -> Decimal( "0.1000000000000000055511151231257827021181583404541015625" ) Decimal( "0.1" ) -> Decimal( "0.1" ) Decimal( "0.10" ) -> Decimal( "0.10" ) Decimal( "7.325" ).quantize( Decimal( ".01" ), rounding = ROUND_DOWN ) -> Decimal( "7.32" ) Decimal( "7.325" ).quantize( Decimal( "1." ), rounding = ROUND_UP ) -> Decimal( "8" ) # Decimal objects cannot generally be combined with floats in arithmetic operations Decimal( 5 ) + 5.0 -> TypeError ``` ###### Abstract Base Classes Supports `isinstance` and `issubclass` functions. - `int` is considered a subclass of `Integral` - `float` is considered a subclass of `Real` - `decimal.Decimal` is considered a subclass of `Number` ```python numbers import Complex, Integral, Number, Rational, Real Number > Complex > Real > Rational > Integral ``` ## Collections ``` Sequence -> ordered collection with indexing and slicing Immutable -> bytes, range, str, tuple Mutable -> bytearray, list Set -> unordered collection of distinct, hashable objects; no indexing or slicing Immutable -> frozenset Mutable -> set Mapping -> ordered collection of value objects indexed by arbitrary hashable key objects Mutable -> dict (preserves order) Callable -> functions, methods, classes, instances that define __call__ ``` #### Slicing ```python a[ i:j ] # returns list of elements starting at i and stopping before j a[ i:j:s ] # s = "step"; aka "extended slice" a[ i:j ] = iterable # replace slice with contents of iterable a[ i:i ] = iterable # insert contents of iterable before position i del a[ i:j ] # element deletion ``` #### ABC Abstract base classes for testing whether a class provides a particular interface. Some simple interfaces are recognizable by the presence of required methods: ```python class E: def __iter__( self ): ... def __next__( next ): ... issubclass( E, Iterable ) -> True isinstance( E(), Iterable ) -> True ``` Complex interfaces do not support this technique because an interface is more than a set of methods — they specify semantics and relationships between methods that cannot be inferred from method presence. For example, knowing that a class supplies `__getitem__`, `__len__`, and `__iter__` is insufficient for distinguishing a `Sequence` from a `Mapping`. ```python class C( Sequence ): def __getitem__( self, key ): ... def __len__( self ): ... def __iter__( self ): ... ``` | Class | Required Methods | Inherited Methods | | ------------------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------- | | Container | `__contains__` | | | Hashable | `__hash__` | | | Iterable | `__iter__` | | | Iterator < Iterable | `__next__` | `__iter__` | | Reversible < Iterable | `__reversed__` | | | Generator < Iterator | `send`, `throw` | `close`, `__iter__`, `__next__` | | Sized | `__len__` | | | Callable | `__call__` | | | Collection < Sized Iterable Container | `__contains__`, `__iter__`, `__len__` | | | Sequence < Reversible Collection | `__getitem__`, `__len__` | `__contains__`, `__iter__`, `__reversed__`, `index`, `count` | | MutableSequence < Sequence | `__getitem__`, `__setitem__`, `__delitem__`, `__len__`, `insert` | Sequence methods + `append`, `reverse`, `extend`, `pop`, `remove`, `__iadd__` | | ByteString < Sequence | `__getitem__`, `__len__` | Sequence methods | | Set < Collection | `__contains__`, `__iter__`, `__len__` | `__le__`, `__lt__`, `__eq__`, `__ne__`, `__gt__`, `__ge__`, `__and__`, `__or__`, `__sub__`, `__xor__`, `isdisjoint` | | MutableSet < Set | `__contains__`, `__iter__`, `__len__`, `add`, `discard` | Set methods + `clear`, `pop`, `remove`, `__ior__`, `__iand__`, `__ixor__`, `__isub__` | | Mapping < Collection | `__getitem__`, `__iter__`, `__len__` | `__contains__`, `keys`, `items`, `values`, `get`, `__eq__`, `__ne__` | | MutableMapping < Mapping | `__getitem__`, `__setitem__`, `__delitem__`, `__iter__`, `__len__` | Mapping methods + `pop`, `popitem`, `clear`, `update`, `setdefault` | | MappingView < Sized | | `__len__` | | ItemsView < MappingView, Set | | `__contains__`, `__iter__` | | KeysView < MappingView, Set | | `__contains__`, `__iter__` | | ValuesView < MappingView, Collection | | `__contains__`, `__iter__` | | Awaitable | `__await__` | | | Coroutine < Awaitable | `send`, `throw` | `close` | | AsyncIterable | `__aiter__` | | | AsyncIterator < AsyncIterable | `__anext__` | `__aiter__` | | AsyncGenerator < AsyncIterator | `asend`, `athrow` | `aclose`, `__aiter__`, `__anext__` | | Buffer | `__buffer__` | | #### APIs ###### Sequences ```python x in s, x not in s s + t, s * n, n * s s[ i ], s[ i:j ], s[ i:j:k ] len( s ), min( s ), max( s ) s.index( x[, i[, j ] ] ) # first occurrence of x in s (or in the slice i:j) # raises ValueError if not found s.count( x ) ``` > [!NOTE] range() > ``` > immutable sequence type > range( stop ) > range( start, stop[, step] ) > r = range( 1, 5 ) > list( r ) -> [ 1, 2, 3, 4] > len( r ) -> 4 > 4 in r -> True > 5 in r -> False > ``` ###### Mutable Sequences ```python s[ i ] = x s[ i:j ] = t s[ i:j:k ] = t del s[ ... ] s.append( x ) s.clear() s.copy() # returns shallow copy; same as s[:] s.extend( t ) # same as: s += t s *= n s.insert( i, x ) # same as: s[ i:i ] = x s.pop( i=-1 ) # remove and return element at i s.remove( x ) # remove first occurence s.reverse() # in-place list.sort( *, key=None, reverse=False ) # in-place ``` ###### Sets ```python e in s len( s ) for e in s: s.add( elem ) s.update( *iter ) # add elements from zero or more iterables s.remove( elem ) s.isdisjoint( other ) # True if intersection of sets is empty s <= other s.issubset( other ) # True if subset or equal s < other # True if subset and not equal s >= other s.issuperset( other ) s > other s | other | ... s.union( *others ) s & other & ... s.intersection( *others ) s - other - ... s.difference( *others ) s ^ other s.symmetric_difference( other ) s.copy() ``` ###### Mappings (Dicts) ```python dict.fromkeys( iterable[, value] ) # iterable of keys plus optional value list( d ) # -> list of keys tuple( d ) # -> tuple of keys len( d ) # -> int of item count d[ key ] # -> returns value or calls __missing__() or raises KeyError d[ key ] = value del d[ key ] # -> raises KeyError key in d, key not in d iter( d ) # -> iter for keys; shortcut for iter( d.keys() ) d.clear() d.copy() # -> shallow copy d.get( key[, default] ) d.items() # -> dict_items| ( k1, v1 ), ... | d.keys() # -> dict_keys| k1, ... | d.pop( key[, default] ) # remove and return value or return default or raise KeyError d.popitem() # LIFO order; -> ( k, v ) reversed( d ) # -> iter for keys in reverse; shortcut for reversed( d.keys() ) d.setdefault( key, default=None ) d.update( other ) d.values() # -> dict_values| v1, ... | d | other # returns new merged dict; other has priority d |= other # equiv to d.update( other ) # dict_items, dict_keys, and dict_values are "Dictionary View" classes. ``` ###### Dictionary View Objects ```python len( dv ) iter( dv ) x in dv reversed( dv ) dv.mapping # -> original dict # `dict_keys` also supports set operations ``` ## Collections Module ```python3 ChainMap < MutableMapping # virtual view of multiple mappings Counter < dict # for counting hashable objects defaultdict < dict # calls factory function to supply missing values deque < object # list-like, with fast mutations on either end namedtuple() # factory function for creating tuple subclasses # with named fields accessible as attributes OrderedDict < dict # OBSOLETE (only trivial differences from normal dicts) UserDict < MutableMapping # wrapper around dict objects for easier subclassing UserList < MutableMapping # wrapper around list objects for easier subclassing UserString < Sequence # wrapper around str objects for easier subclassing ``` ###### ChainMap ```python cm = ChainMap( *maps ) cm.maps ``` - like `dict` but with `.maps` attribute - lookups search the maps in order - mutations only touch the first mapping ###### Counter - For new keys, inits `0` instead of `None`. - For missing keys, returns `0` instead of raising `KeyError`. - Objects be compared for equality and superset/subset relationships. - Objects be added and subtracted. ```python cnt = Counter( [iter-or-map] ) # For new keys, inits 0 instead of None. # For missing keys, returns 0 instead of raising KeyError. cnt = Counter( words ) -or- cnt = Counter() for word in words cnt[ word ] += 1 cnt[ word ] # returns 0+ cnt.elements() # returns iterator: # each key K, in occurrence order, repeated cnt[ k ] times cnt.most_common( [n] ) # if None, returns all, ordered most to least # if n, returns top n # n=3 -> [ ( 'foo', 13 ), ( 'bar', 8 ), ( 'baz', 7 ) ] cnt.subtract( [iter-or-map] ) # decrement counter for each occurence cnt.total() # sum of counts cnt.update( [iter-or-map] ) # increments counts instead of replacing values ``` ###### defaultdict ```python defaultdict( default_factory=None, **kwargs ) ``` `default_factory` should be a callable that takes no arguments. It will be called to initialize the value of missing keys. ###### namedtuple() Returns custom subclass of `tuple` named `typename` with named fields accessible as attributes and helpful docstring and `__repr__()` implementation. The subclass constructor will accept both positional and keyword arguments for those fields. Instances can be used anywhere a regular tuple can be. ```python namedtuple( typename, field_names, *, rename=False, defaults=None, module=None ) # field_names -> either a list of strings, or a string of field names # separated by whitespace and/or commas # defaults -> an optional list of default values (applied from the right side) # module -> set __module__ attribute (defaults to current module) Point = namedtuple( "Point", [ "latitude", "longitude" ] ) Point = namedtuple( "Point", "latitude longitude" ) p = Point( 1.2, 3.4 ) p = Point( longitude=3.4, latitude=1.2 ) p.latitude # -> 1.2 p[ 0 ] # -> 1.2 # extra attributes (beyond standard tuple API) p._asdict() # -> { ... } p._replace( **kwargs ) # -> new Point with replaced values p._fields # -> ( 'latitude', 'longitude' ) p._field_defaults # -> { field: default } ``` ###### User* classes The `User`* classes simulate their respective built-in types, and were created to facilitate subclassing. Now you can subclass directly from `dict`, `list`, and `str`. However, these classes can be easier to work with because the underlying contents are stored in a `data` attribute. ```python UserDict( [initialdata] ) .data -> actual dict (stores contents) UserList( [list] ) .data -> actual list (stores contents) UserString( seq ) .data -> actual str (stores contents) ``` ## Iterators and Generators ```python iterator = container.__iter__() iterator.__iter__() # return self iterator.__next__() # return next item or raise StopIteration ```