Nick Coghlan wrote:
Steven Bethard wrote:

It was because these seem like two separate cases that I wanted two different functions for them (__init__ and, say, dictview)...
I see this, but I think it weakens the case for a single implementation, given that each implementation is essentially one method.

The other issue is that a namespace *is* a mutable object, so the default behaviour should be to make a copy


I don't follow this argument. Why does mutability demand copy? Given that somedict here is either a throwaway (in the classic bunch application ) or a dict that must be updated (the wrap-dict case), copying doesn't make much sense to me.

OTOH, dict.__init__(dict) copies.  hmmmm....


I think Michael's implementation also fell into a trap whereby 'E' couldn't be used as an attribute name. The version below tries to avoid this (using magic-style naming for the other args in the methods which accept keyword dictionaries).

You're right - I hadn't considered that. In case it wasn't obvious, I was matching the argspec of dict. Your solution avoids the problem.

To limit the special casing in update, I've switched to only using __dict__ for the specific case of instances of namespace

That seems a pity to me. (otherwise the
semantics are too hard to explain). This is to allow easy copying of an existing namespace -

Can't this be spelled namespace(somenamespace).__copy__()?

> for anything else, invoking vars() is easy enough.

If there is potential for confusion, I'd be tempted to disallow namespaces as an argument to update/__update__

We could use __add__, instead for combining namespaces


And I was reading Carlos's page on MetaTemplate, so I threw in an extra class "record" which inherits from namespace and allows complex data structures to be defined via class syntax (see the record.__init__ docstring for details). That bit's entirely optional, but I thought it was neat.

Good idea. The implementation ought to be tested against several plausible specializations.

Finally, I've just used normal names for the functions. I think the issue of function shadowing is best handled by recommending that all of the functions be called using the class explicitly - this works just as well for instance methods as it does for class or static methods.

I don't like the sound of that. The whole point here - whether as Steven's nice straightforward bunch, as originally conceived, or the other cases you and I and others have been 'cluttering' the discussion with ;-) is convenience, and readability. If there are hoops to jump through to use it, then the benefit is quickly reduced to zero.


Regards

Michael


Cheers, Nick.

+++++++++++++++++++++++++++++++++++++++++++++

from types import ClassType

class namespace(object):
    """
    namespace([namespace|dict]) => object

    namespace objects provide attribute access to their __dict__
    Complement of vars:  vars(object) => object.__dict__

    Non-magic methods should generally be invoked via the class to
    avoid inadvertent shadowing by instance attributes

    Using attribute names that look like magic attributes is not
    prohibited but can lead to surprising behaviour.

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

    def __init__(__self__, __orig__ = None, **__kwds__):
        """__init__([namespace|dict], **kwds) -> None"""
        type(__self__).update(__self__, __orig__, **__kwds__)

    @classmethod
    def view(cls, orig):
        """namespace.view(dict) -> namespace

        Creates a namespace that is a view of the original
        dictionary. Allows modification of an existing
        dictionary via namespace syntax"""
        new = cls()
        new.__dict__ = orig
        return new

    def __repr__(self):
        return "%s(%s)" % (self.__class__.__name__, repr(self.__dict__))

    # Recommend calling non-magic methods via class form to
    # avoid problems with inadvertent attribute shadowing
    def _checked_update(self, other):
        try:
            self.__dict__.update(other)
        except (TypeError):
            raise TypeError("Namespace update requires mapping "
                            "keyed with valid Python identifiers")

def update(__self__, __other__ = None, **__kwds__):
"""type(self).update(self, [namespace|dict], **kwds) -> None
equivalent to self.__dict__.update"""
# Handle direct updates
if __other__ is not None:
if isinstance(__other__, namespace):
type(__self__)._checked_update(__self__, __other__.__dict__)
else:
type(__self__)._checked_update(__self__, __other__)
# Handle keyword updates
if __kwds__ is not None:
type(__self__)._checked_update(__self__, __kwds__)



class record(namespace): def __init__(self, definition=None): """record([definition]) -> record

        Constructs a namespace based on the given class definition
        Nested classes are created as sub-records
        Fields starting with an underscore are ignored
        If definition is not given, uses current class
        This is handy with subclasses
        Using subclasses this way has the advantage that the
        created records are also instances of the subclass.

        For example:
        Py> from ns import namespace, record
        Py> class Record:
        ...   a = 1
        ...   b = ""
        ...   class SubRecord:
        ...     c = 3
        ...
        Py> x = record(Record)
        Py> x
        record({'a': 1, 'b': '', 'SubRecord': record({'c': 3})})
        Py> class Record2(record):
        ...   a = 1
        ...   b = ""
        ...   class SubRecord2(record):
        ...     c =3
        ...
        Py> x = Record2()
        Py> x
        Record2({'a': 1, 'b': '', 'SubRecord2': SubRecord2({'c': 3})})
        """
        cls = type(self)
        if definition is None:
            definition = cls
        cls.update_from_definition(self, definition)

    def update_from_definition(self, definition):
        """type(self).update_from_definition(self, definition) -> None

Updates the namespace based on the given class definition
Nested classes are created as sub-records
Fields starting with an underscore are ignored"""
try:
for field, default in definition.__dict__.iteritems():
if field.startswith("_"):
continue
if (isinstance(default, (type, ClassType))
and issubclass(default, record)):
# It's a record, so make it an instance of itself
self.__dict__[field] = default()
else:
try:
# If we can make a record of it, do so
self.__dict__[field] = record(default)
except TypeError:
# Throw it in a standard field
self.__dict__[field] = default
except AttributeError:
raise TypeError("Namespace definition must have __dict__ attribute")



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

Reply via email to