A Type for sys.implementation ● Python implementation specifics: PEP 421 ● the type must communicate the nature of the namespace ● dict too soft ● namedtuple too hard
A Type for sys.implementation ● Python implementation specifics: PEP 421 ● the type must communicate the nature of the namespace ● dict too soft ● namedtuple too hard ● object just right...
A Type for sys.implementation ● Python implementation specifics: PEP 421 ● the type must communicate the nature of the namespace ● dict too soft ● namedtuple too hard ● object just right... ● types.SimpleNamespace
How they work: obj[key] obj[key] = value del obj[key] key in obj obj.__getitem__(key) obj.__setitem__(key, val) obj.__delitem__(key) obj.__contains__(key)
How they work: obj[key] obj[key] = value del obj[key] key in obj collections.abc.(Mutable)Mapping obj.__getitem__(key) obj.__setitem__(key, val) obj.__delitem__(key) obj.__contains__(key)
property-based containers (static namespaces) ● a proper name aliases an underlying key ● the key is associated with a value ● the names and values are fixed in place (i.e. read-only)
namedtuple: context + names Spam = namedtuple('Spam', "a b c") class Spam(tuple): def __new__(cls, a, b, c): return super().__new__(cls, a, b, c) @property def a(self): return self[0] ...
How __getattribute__() works: 1. use a "data" descriptor, if there is one 2. pull from the instance, if it has __dict__ 3. use a "non-data" descriptor, if there is one 4. use __getattr__(), if there is one 5. raise AttributeError
How __getattribute__() works: 1. use a "data" descriptor, if there is one 2. pull from the instance, if it has __dict__ 3. use a "non-data" descriptor, if there is one 4. use __getattr__(), if there is one 5. raise AttributeError
How __getattribute__() works: 1. use a "data" descriptor, if there is one 2. pull from the instance, if it has __dict__ 3. use a "non-data" descriptor, if there is one 4. use __getattr__(), if there is one 5. raise AttributeError MRO!
How __getattribute__() works: 1. use a "data" descriptor, if there is one 2. pull from the instance, if it has __dict__ 3. use a "non-data" descriptor, if there is one 4. use __getattr__(), if there is one 5. raise AttributeError Method Resolution Order!
Objects ● are namespace containers ● have namespaces (mostly) ● ergo, as container, proxies a namespace ● base object type has slots ● assignment/definition: "bind" object to namespace
__dict__ ● most builtins don't have one ● key exception: function objects ● module namespaces exposed as __dict__ ● read-only proxy of class namespaces exposed as __dict__ ● use metaclass __prepare__() to customize the namespace used during class definition
Name lookup: ● explicit lookup happens relative to containers ● Method Resolution Order (MRO) ● lookup on class vs. on objects ● special method lookup ● implicit lookup happens relative to execution namespaces...
sys.modules >>> import mordor Traceback (most recent call last): File ".../mordor.py", line 14, in raise ImportError(boromir_says) ImportError: One does not simply import Mordor.