Alex Martelli wrote:
Steven Bethard <[EMAIL PROTECTED]> wrote:


Hmm... interesting. This isn't the main intended use of Bunch/Struct/whatever, but it does seem like a useful thing to have...
I wonder if it would be worth having, say, a staticmethod of Bunch that
produced such a view, e.g.:


class Bunch(object):
    ...
    @staticmethod
    def view(data):
        result = Bunch()
        result.__dict__ = data
        return result

Then you could write your code as something like:

gbls = Bunch.view(globals())

I'm probably gonna need more feedback though from people though to know
if this is a commonly desired use case...


Reasonably so, is my guess.  Witness the dict.fromkeys classmethod -- it
gives you, on dict creation, the same kind of nice syntax sugar that
wrapping a dict in a bunch gives you for further getting and setting
(and with similar constraints: all keys must be identifiers and not
happen to clash with reserved words).

I think this ``view'' or however you call it should be a classmethod
too, for the same reason -- let someone handily subclass Bunch and still
get this creational pattern w/o extra work.  Maybe a good factoring
could be something like:

class Bunch(object):

    def __init__(self, *a, **k):
        self.__dict__.update(*a, **k)

    def getDict(self):
        return self.__dict__

    def setDict(self, adict):
        self.__dict__ = adict

theDict = property(getDict, setDict, None, "direct access to the instance dictionary"
)


    @classmethod
    def wrapDict(cls, adict, *a, **k):
        result = cls.__new__(cls, *a, **k)
        result.setDict(adict)
        cls.__init__(result, *a, **k)
        return result

I'm thinking of use cases where a subclass of Bunch might override
setDict (to do something else in addition to Bunch.setDict, e.g.
maintain some auxiliary data structure for example) -- structuring
wrapDict as a classmethod in a ``Template Method'' DP might minimize the
amount of work, and the intrusiveness, needed for the purpose.  (I don't
have a real-life use case for such a subclass, but it seems to cost but
little to provide for it as a possibility anyway).

[[given the way property works, one would need extra indirectness in
getDict and setDict -- structuring THEM as Template Methods, too -- to
fully support such a subclass; but that's a well-known general issue
with property, and the cost of the extra indirection -- mostly in terms
of complication -- should probably not be borne here, it seems to me]]


Alex

Steven et al

I like the idea of making the 'bunch' concept a little more standard.
I also like the suggestion Nick Coghlan cited (not sure who suggested the term in this context) of calling this 'namespace' in part because it can lead to easily-explained semantics.


ISTM that 'bunch' or 'namespace' is in effect the complement of vars i.e., while vars(object) => object.__dict__, namespace(somedict) gives an object whose __dict__ is somedict.

Looked at this way, namespace (or bunch) is a minimal implementation of an object that implements the hasattr(object,__dict__) protocol. The effect of the class is to make operations on __dict__ simpler. namespace instances can be compared with any other object that has a __dict__. This differs from the PEP reference implementation which compares only with other bunch instances. In practice, comparisons with module and class may be useful.

The class interface implements the protocol and little else.

For 'bunch' applications, namespace can be initialized or updated with keyword args (just like a dict)
i.e.,
>>> bunch = namespace({"a":1,"b":2})
can also be written as
>>> bunch = namespace(a=1,b=2)


For dict-wrapping applications:
 >>> wrappeddict = namespace(bigdict)
but, unlike the PEP implmentation, this sets wrappeddict.__dict__ = bigdict

I think that this interface allows for either use case, without introducing 'fromdict' classmethod.

Some dict-operations e.g., __copy__ might carry over to the namespace class

Michael


An implementation follows:


# An alternative implementation of Steven Bethard's PEP XXX 'bunch' with # slightly different interface and semantics:

class namespace(object):
    """
    namespace(somedict) => object (with object.__dict__ = somedict)
    NB, complement of vars:  vars(object) => object.__dict__

    namespace objects provide attribute access to their __dict__

    In general, operations on namespace equate to the operations
    on namespace.__dict__

    """

    def __init__(self, E = None, **F):
        """__init__([namespace|dict], **kwds) -> None"""
        if isinstance(E, dict):
            self.__dict__ = E
        elif hasattr(E, "__dict__"):
            self.__dict__ = E.__dict__
        self.__dict__.update(**F)

    # define only magic methods to limit pollution
    def __update__(self, E = None, **F):
        """update([namespace|dict], **kwds) -> None
        equivalent to self.__dict__.update
        with the addition of namespace as an acceptable operand"""
        if hasattr(other, "keys"):
            self.__dict__.update(E)
        elif hasattr(other, "__dict__"):
            self.__dict__.update(E.__dict__)
        self.__dict__.update(**F)
    def __repr__(self):
        return "namespace(%s)" % repr(self.__dict__)

    # Possible additional methods:  (All are conveniences for dict operations
    # An operation on namespace translates operation on namespace.__dict__
    # So A op B => A.__dict__ op B.__dict__)

    def __copy__(self):
        return namespace(self.__dict__.__copy__)
    def __eq__(self, other):
        return self.__dict__ == other.__dict__

    def __contains__(self, key):
        return self.__dict__.__contains__(key)
    def __iter__(self):
        return iter(self.__dict__)
    # etc...

--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to