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

Namespaces in Python by Eric Snow

Namespaces in Python by Eric Snow

PyCon 2013

March 18, 2013

Transcript

80 slides
  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

More Decks by PyCon 2013

Other Decks in Technology