# 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 ```