Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Namespaces in Python by Eric Snow

PyCon 2013
March 18, 2013

Namespaces in Python by Eric Snow

PyCon 2013

March 18, 2013
Tweet

More Decks by PyCon 2013

Other Decks in Technology

Transcript

  1. "Namespaces are one honking great idea -- let's do more

    of those!" - Tim Peters, The Zen of Python
  2. A concept: a set of independently identifiable expectations + a

    unique (within set) label for each member
  3. A concept: a set of independently identifiable expectations + a

    unique (within set) label for each member context + name => value
  4. Namespaces in C? PyObject Py_TYPE PyDict_SetItem PyErr_SetString Py_None Py .

    Object Py . TYPE Py . Dict . SetItem Py . Err . SetString Py . None
  5. A Type for sys.implementation • Python implementation specifics: PEP 421

    • the type must communicate the nature of the namespace
  6. A Type for sys.implementation • Python implementation specifics: PEP 421

    • the type must communicate the nature of the namespace • dict too soft
  7. 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
  8. 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...
  9. 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
  10. Some available types: • dict • collections.defaultdict • collections.OrderedDict •

    configparser.ConfigParser • shelve.Shelf • types.MappingProxyType • weakref.WeakKeyDictionary • weakref.WeakValueDictionary
  11. 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)
  12. 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)
  13. class ReadOnlyProxy(Mapping): def __init__(self, mapping): self._mapping = mapping def __len__(self):

    return len(self._mapping) def __iter__(self): return iter(self._mapping) def __getitem__(self, key): return self._mapping[key]
  14. Gems: • dict(mapping, **other_mapping) • d.update(mapping, **other_mapping) • dict.from_keys() •

    dict.setdefault() • str.formatmap() • operator.itemgetter() • threading.local
  15. 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)
  16. Example: >>> sys.version_info sys.version_info(major=3, minor=4, micro=0, releaselevel='alpha', serial=0) >>> os.times()

    posix.times_result(user=0.09, system=0.04, children_user=0.0, children_system=0.0, elapsed=17248877.17)
  17. 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] ...
  18. class ReadOnlyProxy: def __init__(self, obj): self._obj = obj @property def

    spam(self): return self._obj.spam @property def eggs(self): return self._obj.eggs
  19. 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
  20. 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
  21. 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!
  22. 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!
  23. Some available types: • object • types.SimpleNamespace • argparse.Namespace •

    multiprocessing.Manager.Namespace • xmlrpc.client.ServerProxy • unittest.Mock
  24. Objects • are namespace containers • have namespaces (mostly) •

    ergo, as container, proxies a namespace >>> ns = SimpleNamespace() >>> ns_ns = vars(ns) >>> ns.__dict__ is ns_ns True
  25. Objects • are namespace containers • have namespaces (mostly) •

    ergo, as container, proxies a namespace • base object type has slots • assignment/definition: "bind" object to namespace
  26. Object access helpers: • getattr() • setattr() • delattr() •

    hasattr() wrapper around getattr() • dir() calls obj.__dir__() • vars() exposes namespace* • inspect.getattr_static() • inspect.getmembers()
  27. __dict__ • most builtins don't have one • key exception:

    function objects • module namespaces exposed as __dict__
  28. __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
  29. Name lookup: • explicit lookup happens relative to containers •

    Method Resolution Order (MRO) • lookup on class vs. on objects • special method lookup
  30. 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...
  31. Scope (a.k.a. implicit lookup): 1. locals • function execution namespace

    • use vars() or locals() 2. non-locals (closures) 3. globals • module execution namespace • use vars() or globals() 4. builtins • interpreter execution namespace • use builtins or __builtins__
  32. sys.modules >>> import mordor Traceback (most recent call last): File

    ".../mordor.py", line 14, in <module> raise ImportError(boromir_says) ImportError: One does not simply import Mordor.
  33. APIs: mapping-based • see collections.abc.Mapping property-based • use properties +

    "private" attributes attribute-based • __getattribute__() and __getattr__() • __setattr__() • __delattr__()
  34. Helpers: • globals() • locals() • vars() • dir() •

    getattr() • setattr() • delattr() • hasattr() • inspect.getattr_static() • id()
  35. • namespaces: context + name => value • containers: ◦

    mapping-based (volatile) ◦ property-based (static) ◦ attribute-based (stable) • pervasive in Python • rich APIs • rich tools for objects