Python
Introduction
Interpreted programming language, especially popular in machine learning applications.
For a quick reference see here.
Types
Primitive types are Integers, Float, String, Boolean.
Non-primitive data structures are List, Tuple, Dictionary, Set. Time complexity for these are posted here.
These (alongside any other data type) can be used with type signatures, for example:
from typing import Dict, List def foo(x: int | Dict[int, int | float], y: float | None)
Where the a | b (or nested variants) signify that the type could be either a or b.
Standard library
Strings
Math
Random
File management
Package Management
pipreqsis more robust thanpip freezeto generaterequirements.txtfiles.
Object-oriented programming
Functional programming
Libraries
- JAX.
- PyTorch.
- pytest.
- matplotlib.
- prettytable.
- pytest-sugar.
- nodezator.
Debugging
- (Andrej Karpathy)
import code; code.interact(local=locals())is the sweet spot in betweenprint()andimport pdb; pdb.trace(). - See also
IPython.embedwhich does the same but comes with all the benefits of IPython.
Tips
Formatted Printing
name = "Nazaal" test = f"Name {name}" test_2 = f"{name=}" print(test) print(test_2)
When using f-strings, use f"{loss = }" instead of f"{loss = {loss}}".
Gotchas
Storing functions in dictionaries
The following does not work:
def dict_w_fs(n): res = {} for i in range(n): def foo(x): return x*i res[i] = foo # or similarly, res[i] = lambda x: x*i return res
The following works:
def dict_w_fs(n): res = {} for i in range(n): def foo(x, i=i): return x*i res[i] = foo # or similarly, res[i] = lambda x, i=i: x*i return res
Resources
Anki
Give an example of using composition over inheritance.
Personal communication, Ti.
Suppose we have the following class whose functionality we want to use in other classes without reimplemeting it.
class Stateful: def init(self, key): self._key_state = key def _next_key(self): self._key_state, new_key = jax.random.split(self._key_state) return new_key
And we have another class Environment where we want to make use of state via the Stateful class above.
The inheritance approach is:
@dataclass class Environment(Stateful): seed: int def __post_init__(self): self.init(jax.random.PRNGKey(self.seed)) def foo(self, bar): key = self._next_key() ...
The composition approach is:
@dataclass class Environment: seed: int state: Stateful ... def __post_init__(self): self.state = Stateful(self.seed) def foo(self, bar): key = self.state._next_key() ...
When using dataclasses, you can make them slotted so that new attributes cannot be inserted with the dot syntax.
What is the difference between @property from the Protocol class and @abstractmethod from the ABC class?
Protocol classes do not necessarily need to be inherited from for them to be used and can be seen as an interface class, meanwhile ABC requires inheritance. In that sense, using Protocol is more flexible, since any object which implements the methods defined inside it, even from third party packages. Meanwhile, any class Foo which inherits from an abstract base class Bar(ABC) must implement all @abstractmethod's defined.