My fear is that someone will just use a dict literal as stated above and try to create an object with positional arguments:
The problem is that iteration order over a dict is not guaranteed, so this might initialize Point(x=0, y=7) like the use intends, or Point(x=5, y=0). So in this case I want to disable positional arguments. However, positional arguments for initializing struct are pretty convenient, so I would like to make that available as far as possible. An implementation using Ordered might look like this:
class BasicStruct(object):
"""Class for holding struct-like objects."""
__slots__ = () # should be extended by deriving classes
def __init__(self, *args, **kwargs):
default_values = isinstance(self.__slots__, Mapping)
ordered = isinstance(self.__slots__, Ordered)
if args and not ordered:
raise ValueError("Can't pass non-keyword arguments to {}, since "
"__slots__ was declared with an unordered "
"iterable.".format(self.__class__.__name__))
arg_pairs = zip(self.__slots__, args)
for key, value in chain(arg_pairs, six.iteritems(kwargs)):
setattr(self, key, value)
for key in self.__slots__:
if not hasattr(self, key):
default_value = None
if default_values:
default_value = self.__slots__[key]
setattr(self, key, default_value)
This will allow users who are interested in positional argument initialization to use an Ordered mapping (such as OrderedDict, or a custom collection).
I would like to emphasize again that the most compelling reason for me that this should be part of the stdlib is that there is no workaround for this that also allows users to use ordered custom collections. There is no way to check for "promised ordering" in any functional manner.