# Python : Core : Language
- [reference/lexical_analysis](https://docs.python.org/3/reference/lexical_analysis.html)
- [reference/expressions](https://docs.python.org/3/reference/expressions.html)
- [reference/simple_stmts](https://docs.python.org/3/reference/simple_stmts.html)
- [reference/compound_stmts](https://docs.python.org/3/reference/compound_stmts.html)
#### Basics
- indentation matters; cannot mix tabs and spaces
- join *physical lines* into a *logical line* with `\` at end of line
- tokens: *identifiers*, *keywords*, *literals*, *operators*, and *delimiters*
- *statements* require their own logical line, while *non-statement expressions* can coexist in a single logical line (aka "inline")
- *simple statements* can be combined on a physical line use semicolon separators: `pass ; pass`
- *compound statements* are statements containing other statements (a *suite*), and cannot be combined using semicolons
- `class`, `def`, `for`, `if`, `match`, `try`, `while`, `with`
###### Identifiers aka Names
- starts with underscore -> not included by `import *`
- starts with `__*` -> *class-private* names
- pattern: `__*__` -> system-defined names (including [[Special Methods]])
###### Keywords
```python
False assert continue except if nonlocal return
None async def finally import not try
True await del for in or while
and break elif from is pass with
as class else global lambda raise yield
# "soft keywords"
_ case match type
```
###### Literals
```python
# Built-in Names / Constants
True, False, None, NotImplemented, Ellipsis, ..., __debug__
# Numbers
0b1010, 0o7654, 0xfe12, 2.537E5, 1_234
float( 'NaN' ), decimal.Decimal( 'NaN' )
# Strings
# - escapes include \N{name}, \uxxxx, \Uxxxxxxxx
# - adjecent literals are concatenated: "hello " "world"
"...", '...' # single line
"""...""", '''...''' # multiline
b"...9" # bytes instead of str
r"..." # "raw" (no escapes)
f"...{ }..." # f-strings (formatted strings)
# Escapes
# \\ \' \" \f -> formfeed \n \r \t \v -> vertical tab
# \a -> bell, \b -> backspace, \ooo -> octal, \xhh -> hex
# Collections
[ i1, ... ] # list
{ k1: v1, ... } # dict
( i1, ... ) # tuple (really, it's the comma)
{ i1, ... } # set
```
> [!info] Tuples & Parentheses
> ```python
> ( x ) -> x
> ( x, ) -> tuple of length 1
> ```
###### Operators
```python
+ - * ** / // % @
<< >> & | ^ ~
< > <= >= == !=
:= # assignment expression operator (aka walrus)
in, not in # membership test - uses __contains__(), __iter__(), or __getitem__() with ints
# works on all built-in collections sequences, including strings
is, is not # identity comparison - uses id()
x if C else y # ternary operator
# Packing / Unpacking
*foo # iterable
**foo # dictionary
# Division & Modulo
3 / 2 = 1.5 -but- 3 // 2 = 1 # floor division
10 % 3 == 1 # modulo
x == ( x // y ) * y + ( x % y )
# Shift Operations
x << y # shift left; new bits on right are zeros; same as multiplying x by 2**y
x >> y # shift right; same as //'ing x by 2**y
x & y # bitwise and
x | y # bitwise or
~ x # complement of x (swapping 1s and 0s); same as -x - 1
x ^ y # bitwise xor
```
- ints are converted to floats when interacting with floats
- you can multiply a sequence: `2 * [3,4] == [3,4,3,4]`
- you can add sequences: `[1,2] + [5,6] == [1,2,5,6]`
- comparisons can be chained: `x < y <= z -eq- x < y and y <= z`
- comparison operators compare built-in types by value (including collections)
- `set` comparisons are for superset / subset relationships
- subclasses of `object` compare by identity, and only implement `==` and `!=`
###### Delimeters
Some delimiters are also operators.
```python
( ) [ ] { }
, : . ; @ ->
# assignment operator (statement)
= # also: a, b = 1, 2
# augmented assignment operators (statements)
+= -= *= /= //= %= @=
&= |= ^= >>= <<= **=
```
###### Comprehensions aka "Displays"
```python
( i for i in iterable if exp ) # generator expression (yields generator object)
[ i for i in iterable if exp ] # list
{ i for i in iterable if exp } # set
{ k: v for i in iterable if exp } # dict
# nesting
[ f"{i}{j}" for i in range(3) for j in range(i) ] -> [ "10", "20", "21" ]
```
#### Statements
###### Misc
```python
global foo, ... # allow assignment to these global vars in local context
nonlocal foo, ... # allow assignment to these vars in enclosing (but NOT global) scope
# Assertions
assert exp # eq: if __debug__ and not exp: raise AssertionError
assert exp, msg # eq: if __debug__ and not exp: raise AssertionError( msg )
# __debug__ is normally True; False when optimization requested (-O)
# Deletions
del a, b, c # works for: names, attributes, subscriptions
```
###### Context Managers
```python
with exp[ as bar]: ... # exp must return context manager with __enter__ and __exit__
# __enter__ is invoked, and the return value assigned to bar
# after suite executes, __exit__ is invoked
with A() as a, B() as b: ...
```
###### Control Flow
```python
if exp: ...
elif exp: ...
else: ...
while exp: ...
else: ... # if loop ended normally - without `break`
for x in y: ...
else: ... # if loop ended normally - without `break`
# uses Structural Pattern Matching (PEP 634)
flag = False
match ( 100, 200 ): # subject expr
case ( 100, 300 ): # mismatch: 200 != 300
print( "Case 1" )
case ( 100, 200 ) if flag: # successful match, but guard fails
print( "Case 2" )
case ( 100, y ): # matches and binds y to 200
print( f"Case 3, y: {y}" ) # -> "Case 3, y: 200"
case _: # pattern not attempted
print( "Case 4, I match anything!" )
```
###### Functions
- function and class definitions are executable statements that bind the name in the local context
- *params* are the names in the definition
- *arguments* are the values in the invocation
```python
# stubs
def foo(): ...
def foo(): "docstring"
# full syntax
def foo( param1, ..., /, paramX, ..., *[args], paramY=default, ..., **[kwarwgs] )
"""docstring"""
...
```
- Parameters without default values must come before the others.
- Parameters before `/` are positional-only parameters and may only be passed by positional arguments.
- Parameters after `*` or `*args` are keyword-only parameters and may only be passed by keyword arguments.
- Avoid default values like `[]`; use `None`, then create an empty list inside the function.
- During invocation, positional args must come before keyword args: `f( 1, foo=42 )`
> [!info] Decorators
> ```python
> @f1( arg )
> @f2
> def func(): pass
> ```
> ...is roughly equivalent to...
> ```python
> def func(): pass
> func = f1( arg )( f2( func ) )
> ```
> [!info] lambdas
> ```python
> f = lambda SIGNATURE: EXPRESSION # lambda a, b: a + b
> ```
> - SIGNATURE supports all the features available when defining conventional functions
> - the result of EXPRESSION will be returned from the function
###### Classes
```python
# stubs
class Foo: ...
class Foo: "docstring"
# full syntax
class Foo( parent1, ... ):
"""docstring"""
...
```
- The order in which attributes are defined in the class body is preserved in the new class’s `__dict__`. *Note that this is reliable only right after the class is created and only for classes that were defined using the definition syntax.*
#### Importing
```python
import foo # foo imported and bound locally
import foo.bar.baz # foo, foo.bar, and foo.bar.baz imported, foo bound locally
import foo.bar.baz as fbb # foo, foo.bar, and foo.bar.baz imported, foo.bar.baz bound as fbb
from foo.bar import baz # foo, foo.bar, and foo.bar.baz imported, foo.bar.baz bound as baz
from foo import attr # foo imported and foo.attr bound as attr
from foo import * # imports contents of __all__ or all names that don't begin with underscore
from . import foo # import foo from current dir
from .. import foo # import foo from dir above current
from ... import foo # import foo from dir two levels above current
from ...foo import bar # import bar from foo module in dir two levels above current
importlib.import_module() for dynamically loading modules
```
## Built-In Attributes
#### Module
Docs strongly recommend using `__spec__` instead of `__cached__`, `__loader__`, or `__package__`.
```python
set( dir( mod ) ) == set( mod.__dict__.keys() ) == {
'__all__', '__builtins__', '__cached__', '__doc__', '__file__',
'__loader__', '__name__', '__package__', '__spec__'
}
__annotations__ # dict of variable annotations
__cached__ # the path to any compiled version of the code
__dict__ # (read-only) module namespace; m.x = 1 -> m.__dict__[ "x" ] = 1
__doc__ # docstring or None
__file__ # path to module (if exists)
__loader__ # object used to load module
__name__ # module name
__package__ # if top-level module -> empty string
# if module inside package -> package name
# if package module -> same as __name__
__path__ # if not None, module is a package
# like sys.path, but for importing this package's modules
__spec__ # the module spec used for importing
# implementation-specific
__builtins__ # reference to `builtins` module
# user-defined
__all__ # list of names that will be imported by `import *`
```
###### Module Spec
[importlib.machinery.ModuleSpec](https://docs.python.org/3/library/importlib.html#importlib.machinery.ModuleSpec)
```python
spec.cached # like __cached__
spec.has_location # True if origin refers to a loadable location
spec.loader # like __loader__
spec.name # like __name__
spec.origin # like __file__
spec.parent # like __package__
spec.submodule_search_locations # like __path__
```
#### Function
```python
__annotations__ dict of param annotations ("return" -> return annotation)
__closure__ (read-only) None or tuple of "cells" (advanced)
__code__ code object
__defaults__ None or tuple of default arg values
__dict__ namespace for arbitrary function attributes (foo.answer = 42)
__doc__ docstring or None
__globals__ (read-only) dict of the module namespace in which the func was defined
__kwdefaults__ dict of default kwarg values
__module__ None or module name
__name__ name
__qualname__ qualified name (dotted-path within a module: "MyClass.foo")
__type_params__ tuple of type params of a generic function (???)
```
###### Method
```python
__doc__ ...
__func__ function object
__module__ ...
__name__ ...
__qualname__ ???
__self__ (read-only) class or instance
```
#### Class
```python
__annotations__ dict of variable annotations
__bases__ tuple, in order ???
__dict__ class namespace # c.x = 1 -eq- c.__dict__[ "x" ] = 1
__doc__ ...
__module__ name of the module the class was defined in
__name__ name
__qualname__ ???
__subclasses__ ???
__type_params__ tuple of type params of a generic class ???
```
###### Instance
```python
__class__ class object
__dict__ instance attributes
```