This class wraps any object, and allows accessing and modifying that object's properties using the dict interface. This wrapper is meant to provide a clean interface to getattr/setattr/hasattr/delattr.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | class attrview(object):
"""Wrapper class that provides a dictionary-style, dynamic access to
the properties of the wrapped object. Any mutating map operations
done to the wrapper mutate the wrapped object.
Because objects may implement attributes using __getattr__ and
friends, and there is no __dir__ method for objects to specify
these attributes, it is not possible to enumerate the attributes
of an object in general. attrview does not implement the parts of
the dictionary interface that assume the set of keys is
deterministic. Notably, __iter__, keys, values, and items are
unimplemented.
"""
def __init__(self, obj):
"""Return an attrview wrapper which provides dictionary-style, dynamic
access to the properties of the wrapped object.
"""
self.__wrapped = obj
def __contains__(self, prop):
"""Return true if the wrapped object has property prop, else False.
"""
return hasattr(self.__wrapped, prop)
def __delitem__(self, prop):
"""Delete the property prop from the wrapped object."""
if not hasattr(self.__wrapped, prop):
raise KeyError(prop)
delattr(self.__wrapped, prop)
def __getitem__(self, prop):
"""Return the value of property prop on the wrapped object."""
if not hasattr(self.__wrapped, prop):
raise KeyError(prop)
return getattr(self.__wrapped, prop)
def __setitem__(self, prop, val):
"""Set the value of property prop on the wrapped object to val."""
setattr(self.__wrapped, prop, val)
def get(self, prop, default=None):
"""Return the value of property prop on the wrapped object if present,
else default.
"""
return getattr(self.__wrapped, prop, default)
def has_key(self, prop):
"""Return true if the wrapped object has property prop, else False.
"""
return hasattr(self.__wrapped, prop)
def setdefault(self, prop, val=None):
"""Return self.get(prop, val). Also set the property prop on the
wrapped object to val if it currently does not exist.
"""
if hasattr(self.__wrapped, prop):
return getattr(self.__wrapped, prop)
else:
setattr(self.__wrapped, prop, val)
return val
def update(self, d, **kw):
"""Update the properties of the wrapped object from d and kw, with the
same semantics as dict.update.
if d has keys, for k in d: self[k] = d[k]
else, for k, v in d: self[k] = v
then, for k in kw: self[k] = kw[k].
"""
if hasattr(d, 'keys'):
for k in d:
self[k] = d[k]
else:
for k, v in d:
self[k] = v
for k, v in kw.iteritems():
self[k] = v
|
In python-dev, during discussion of PEP 363, Calvin Spealman noted that it would be useful to have a wrapper class that provides dictionary-like access to attributes.
Here is my take on the idea. I believe the resulting class is more elegant than get/set/has/delattr, and can express clearly things the original syntax cannot, like attrview(obj)[prop] += 3 or attrview(obj).setdefault(prop, []).append(x)
Though this was suggested as an alternative to a proposed syntax change, I think providing mapping-style access to object properties is generally useful.
As noted in the docstrings, this class does not implement the full mapping interface. Notably, since the set of attributes an object has cannot be reliably determined, attrview objects are not iterable.