empty classes as c structs?

Steven Bethard steven.bethard at gmail.com
Mon Feb 7 13:50:53 EST 2005


Michael Spencer wrote:
> 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.

Do you mean there should be a separate Namespace and Bunch class?  Or do 
you mean that an implementation with only a single method is less useful?

If the former, then you either have to repeat the methods __repr__, 
__eq__ and update for both Namespace and Bunch, or one of Namespace and 
Bunch can't be __repr__'d, __eq__'d or updated.

If the latter (setting aside the fact that the implementation provides 4 
methods, not 1), I would argue that even if an implementation is only 
one method, if enough users are currently writing their own version, 
adding such an implementation to the stdlib is still a net benefit.

>> 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.

Another way to avoid the problem is to use *args, like the current Bunch 
implementation does:

     def update(*args, **kwargs):
         """bunch.update([bunch|dict|seq,] **kwargs) -> None

         Updates the Bunch object's attributes from (if
         provided) either another Bunch object's attributes, a
         dictionary, or a sequence of (name, value) pairs, then from
         the name=value pairs in the keyword argument list.
         """
         if not 1 <= len(args) <= 2:
             raise TypeError('expected 1 or 2 arguments, got %i' %
                             len(args))
         self = args[0]
         if len(args) == 2:
             other = args[1]
             if isinstance(other, Bunch):
                 other = other.__dict__
             try:
                 self.__dict__.update(other)
             except (TypeError, ValueError):
                 raise TypeError('cannot update Bunch with %s' %
                                 type(other).__name__)
         self.__dict__.update(kwargs)

This even allows you to use the keywords __self__ and __orig__ if you're 
sick enough to want to.  It's slightly more work, but I prefer it 
because it's more general.

>> 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.

Is it that much worse to require the following code:

     Namespace.update(namespace, obj.__dict__)

or:

     namespace.udpate(obj.__dict__)

if you really want to update a Namespace object with the attributes of a 
non-Namespace object?

For that matter, do you have a use-case for where this would be useful? 
  I definitely see the view-of-a-dict example, but I don't see the 
view-of-an-object example since an object already has dotted-attribute 
style access...

>> This is to allow easy copying of an existing namespace - 
> 
> Can't this be spelled namespace(somenamespace).__copy__()?

I'd prefer to be consistent with dict, list, set, deque, etc. all of 
which use their constructor for copying.

> We could use __add__, instead for combining namespaces

I don't think this is a good idea.  For the same reasons that dicts 
don't have an __add__ (how should attributes with different values be 
combined?), I don't think Bunch/Namespace should have an __add__.

Steve



More information about the Python-list mailing list