Proposed Mixins for Wide Interfaces
How about adding some mixins to simplify the implementation of some of the fatter interfaces? class CompareMixin: """ Given an __eq__ method in a subclass, adds a __ne__ method Given __eq__ and __lt__, adds !=, <=, >, >=. """ class MappingMixin: """ Given __setitem__, __getitem__, and keys, implements values, items, update, get, setdefault, len, iterkeys, iteritems, itervalues, has_key, and __contains__. If __delitem__ is also supplied, implements clear, pop, and popitem. Takes advantage of __iter__ if supplied (recommended). Takes advantage of __contains__ or has_key if supplied (recommended). """ The idea is to make it easier to implement these interfaces. Also, if the interfaces get expanded, the clients automatically updated. Raymond Hettinger
From: "Raymond Hettinger" <python@rcn.com>
How about adding some mixins to simplify the implementation of some of the fatter interfaces?
class CompareMixin: """ Given an __eq__ method in a subclass, adds a __ne__ method Given __eq__ and __lt__, adds !=, <=, >, >=. """
class MappingMixin: """ Given __setitem__, __getitem__, and keys, implements values, items, update, get, setdefault, len, iterkeys, iteritems, itervalues, has_key, and __contains__.
If __delitem__ is also supplied, implements clear, pop, and popitem.
Takes advantage of __iter__ if supplied (recommended).
Takes advantage of __contains__ or has_key if supplied (recommended). """
The idea is to make it easier to implement these interfaces. Also, if the interfaces get expanded, the clients automatically updated.
I think these are a great idea, *in the context of* an understanding of what we want interfaces to be, say, and do. Are we there yet? ----------------------------------------------------------- David Abrahams * Boost Consulting dave@boost-consulting.com * http://www.boost-consulting.com
How about adding some mixins to simplify the implementation of some of the fatter interfaces?
Can you suggest implementations for these, to be absolutely clear what you mean?
class CompareMixin: """ Given an __eq__ method in a subclass, adds a __ne__ method Given __eq__ and __lt__, adds !=, <=, >, >=. """
What if the "natural" thing to implement is __le__ instead of __lt__? That's the case for sets. Or __gt__ (less likely)?
class MappingMixin: """ Given __setitem__, __getitem__, and keys, implements values, items, update, get, setdefault, len, iterkeys, iteritems, itervalues, has_key, and __contains__.
If __delitem__ is also supplied, implements clear, pop, and popitem.
Takes advantage of __iter__ if supplied (recommended).
Does that mean that if you have __iter__, you don't use keys()? In that case it should implement keys() out of __iter__. Maybe this should be required.
Takes advantage of __contains__ or has_key if supplied (recommended). """
Let's standardize on __contains__, not has_key(). I guess you could provide __contains__ as follows: def __contains__(self, key): try: self[key] except KeyError: return 0 else: return 1 I don't mind if there are some recursions amongst the various implementations; if you don't supply the minimum, the implementation will raise "RuntimeError: maximum recursion depth exceeded".
The idea is to make it easier to implement these interfaces. Also, if the interfaces get expanded, the clients automatically updated.
A similar thing for sequences would be useful too, right? --Guido van Rossum (home page: http://www.python.org/~guido/)
[RH]
How about adding some mixins to simplify the implementation of some of the fatter interfaces?
[GvR]
Can you suggest implementations for these, to be absolutely clear what you mean? -- snip -- What if the "natural" thing to implement is __le__ instead of __lt__? That's the case for sets. Or __gt__ (less likely)?
Yes. Here is some code --------------------------- class CompareMixin: """ Given an __eq__ method in a subclass, adds a __ne__ method Given __eq__ and __lt__, adds !=, <=, >, >=. If supplied, takes advantage of __lte__ for speed. """ def __eq__(self, other): raise NotImplementedError def __ne__(self, other): return not (self == other) def __lt__(self, other): raise NotImplementedError def __lte__(self, other): return self < other or self == other def __gt__(self, other): return not (self <= other) def __gte__(self, other): return not (self < other) ## Example from sets import mixins class BaseSet(object, mixins.CompareMixin): """Common base class for mutable and immutable sets.""" __slots__ = ['_data'] # . . . def issubset(self, other): """Report whether another set contains this set.""" self._binary_sanity_check(other) if len(self) > len(other): # Fast check for obvious cases return False otherdata = other._data for elt in self: if elt not in otherdata: return False return True def __eq__(self, other): self._binary_sanity_check(other) return self._data == other._data def __lt__(self, other): self._binary_sanity_check(other) return len(self) < len(other) and self.issubset(other) __le__ = issubset # optional, but recommended for speed. # Example where gt is the most natural implementation class Anyhoo(CompareMixin): __eq__ = someBigEqualityTest __gt__ = someBigComplexOrderingFunction def __lt__(self, other): return not(self>other or self==other) [RH]
class MappingMixin: """ Given __setitem__, __getitem__, and keys, implements values, items, update, get, setdefault, len, iterkeys, iteritems, itervalues, has_key, and __contains__.
If __delitem__ is also supplied, implements clear, pop, and popitem.
Takes advantage of __iter__ if supplied (recommended).
[GvR]
Does that mean that if you have __iter__, you don't use keys()? In that case it should implement keys() out of __iter__. Maybe this should be required.
Not really. keys() is always required. If __iter__ is supplied, then things like iterkeys(), iteritems(), and itervalues() get computed from __iter__ rather than keys(). My thought on using keys() as part of the minimum specification is that database style interfaces always supply some type of list method. For instance, shelve can be instantly widened with the mixin, no other coding is required. OTOH, I'm not glued to the idea of using keys() as part of the minimum spec. [RH]
Takes advantage of __contains__ or has_key if supplied (recommended). """
[GvR]
Let's standardize on __contains__, not has_key(). I guess you could provide __contains__ as follows:
Makes sense. [RH]
The idea is to make it easier to implement these interfaces. Also, if the interfaces get expanded, the clients automatically updated.
[GvR]
A similar thing for sequences would be useful too, right?
Hmm, listing and concatenation beget repetition; len() and __getitem__() beget slicing. iteration and __cmp__ beget min(), max() For mutable sequences, supplying __setitem__ begets appending, extending, and slice assignment. Supplying __delitem__ begets pop(), remove() and slice deletion. For overachivers, the above are all that are needed for sort(), reverse(), index(), insert(), and count() Would you like me to create a mixin module and put it in the sandbox? Raymond Hettinger
[Raymond Hettinger]
[RH]
How about adding some mixins to simplify the implementation of some of the fatter interfaces?
This is a spur-of-the-moment thought, so it might not be a reasonable comment, but do we care that all of these methods will show up in when using dir() or any other introspective check? While I think the idea is great, it might give this sense that they are really, truly implemented for the class instead of reliant on the other implementations; the side effects of changing one of the required methods might have unexpected consequences for the user. But since I think this is a great idea, I don't want to see it disappear because of this; I guess I better solve my issue. =) Perhaps we can just make sure that this gets documented in both the API and in the doc strings saying that it is from the mixin and what methods it is dependent upon. That should be enough to squash my worry. And yes, if this gets into the core and Raymond does not want to do it, I will help with the doc patches. -Brett C.
This is a spur-of-the-moment thought, so it might not be a reasonable comment, but do we care that all of these methods will show up in when using dir() or any other introspective check? While I think the idea is great, it might give this sense that they are really, truly implemented for the class instead of reliant on the other implementations; the side effects of changing one of the required methods might have unexpected consequences for the user.
dir() *intends* to show methods regardless of whether they are implemented in the class or in a base class. So this doesn't sound like a valid objection. Pydoc shows inherited methods separately. --Guido van Rossum (home page: http://www.python.org/~guido/)
[RH]
How about adding some mixins to simplify the implementation of some of the fatter interfaces?
On second thought, I don't think there's enough here to warrant putting this in the standard library. E.g. the example from BaseSet actually strikes me as indirect: because <= is the natural operation to provide for sets, hanging everything off __lt__ looks forced. Maybe this could go into the Demo directory or in some example or HOWTO. We'll revise this issue when we are going to introduce a standard type or interface hierarchy (not for Python 2.3). --Guido van Rossum (home page: http://www.python.org/~guido/)
[RH]
How about adding some mixins to simplify the implementation of some of the fatter interfaces?
[GvR]
On second thought, I don't think there's enough here to warrant putting this in the standard library. E.g. the example from BaseSet actually strikes me as indirect: because <= is the natural operation to provide for sets, hanging everything off __lt__ looks forced.
Agreed. How about the MappingMixin and SequenceMixin? These both provide much more meat and have more natural attach points (getitem, setitem, delitem).
How about the MappingMixin and SequenceMixin? These both provide much more meat and have more natural attach points (getitem, setitem, delitem).
I'd much rather have a howto that explains all the issues. This stuff is vastly underdocumented. --Guido van Rossum (home page: http://www.python.org/~guido/)
participants (4)
-
Brett Cannon
-
David Abrahams
-
Guido van Rossum
-
Raymond Hettinger