I am suggesting the addition of a collections abstract base class called "Ordered". Its meaning is that a collection's iteration order is part of its API. The bulk of this mail describes a use case for this. The reason I believe that such abstract base class is required is that there is no way to test this behavior in a given class. An ordered collection has the exact same interface as an unordered collection (e.g, dict and OrderedDict), other than a _promise_ of the API that the order in which this collection will be iterated has some sort of meaning (In OrderedDict, it is the order in which keys were added to it.)
As examples, set, frozenset, dict and defaultdict should *not* be considered as ordered. list, OrderedDict, deque and tuple should be considered ordered.
Before I dive into the use case I am presenting, I would like to point out that a similar discussion was already done on the subject (suggesting at first that OrderedDict would abstract-subclass from Sequence) at the following thread* - http://code.activestate.com/lists/python-ideas/29532/. That thread was abandoned largely from a lack of a clear use case, which I hope will be more clear in this suggestion.
I am working on package called basicstruct (https://pypi.python.org/pypi/basicstruct). The way it works is that you define an object that inherits from basicstruct.BasicStruct, define __slots__ , and automatically get behaviors such as a nice __init__, __str__, comparison functions, attribute access, dict-like access, pickleability, etc. It is similar to namedtuple, except that it is mutable.
In the Python documentation, the following is said regarding __slots__:
Any non-string iterable may be assigned to __slots__. Mappings may also be used; however, in the future, special meaning may be assigned to the values corresponding to each key.
Here's how the current__init__ method of BasicStruct looks like:
class BasicStruct(object):
"""Class for holding struct-like objects."""
__slots__ = () # should be extended by deriving classes
def __init__(self, *args, **kwargs):
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):
setattr(self, key, None)
Notice the following line:
arg_pairs = zip(self.__slots__, args)
It assumes that __slots__ defines attributes in a certain order. So as a use I would expect that the following code
class MyStruct(BasicStruct):
__slots__ = ('x', 'y')
MyStruct(0, 1)
... will create a struct in which x is 0 and y is 1.
However, if I define __slots__ as a set, or dict, the result is undefined.
class MyStruct(BasicStruct):
__slots__ = {'x', 'y'} # No order is defined here
MyStruct(0, 1) # Which is which?
So, In BasicStruct's __init__ method it is required to test whether __slots__ was defined with a collection that has a meaningful order. If it was _not_, using non-keyword arguments in __init__ should be forbidden, since the order of __slots__ is arbitrary. Here is how I wish the code would look like:
class BasicStruct(object):
"""Class for holding struct-like objects."""
__slots__ = () # should be extended by deriving classes
def __init__(self, *args, **kwargs):
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):
setattr(self, key, None)
Thanks,
Amir Rachum
* The author of the original thread is Ram Rachum. To avoid some confusion - yes, we are related - Ram is my big brother. It's just so happens that I was looking around for this issue and found that he did so in the past as well.
_______________________________________________
Python-ideas mailing list
Python...@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/
I think you've missed the point of his proposal. It doesn't matter _what_ the order is—insertion order, sorted by __lt__ (possibly with a key function), looked up by a function that maps keys to indices, whatever—only that there is some meaningful order (and that iteration follows that order). If so, your type can declare that it implements Ordered.
Of course the user has to know what that order is and what it means in order to do anything with it. In his example, if you use, say, a blist.sortedlist instead of a list for your slots, then you have to pass positional parameters to the initializer in sorted order instead of in source code order. But if that's what makes sense for your code, then great.
The reason I'm not sure it's helpful is that "ordered in some way that makes sense to me that you don't know about" isn't really that useful of a thing for you to check for me. After all, I can use a blist.sortedlist('bac') and then pass the initializer values in b-a-c order, or use list('bac') and pass them in a-b-c order. Each of those is at least as easy to screw up, and just as wrong, as using a set('bac'), and his code can't possibly check for the first two, so what's the point of checking for the third?
But, whether the proposal is useful or not, it is sufficiently specified.
> At the very least, the author's intended
> comparison function should be introspectable so that client subclasses
> can include validation functions. (I guess you could just use
> "lambda slot: list(self.__slots__).index(slot)" as the key function,
> but that doesn't say much about the conceptual semantics.) Then the
> presence of the ordering function would provide a way to duck-type
> abc.Ordered.
How would you define the comparison function for OrderedDict in a way that makes any semantic sense? Or, for that matter, list? The order is the result of a dynamic sequence of operations that nobody's kept track of and that in general can't be recovered. But it doesn't matter why the values are in some particular order, only that they are. Surely OrderedDict and list are perfectly reasonable types for __slots__, despite the fact that their comparison function doesn't exist.
> I haven't thought carefully about it, but a method with semantics of
> "insert next slot at end according to natural order" (named
> "natural_append"? "ordered_append"? or maybe the existing "append"
> used by sequences could be given this semantic as well?
You're talking about the API for a mutable sorted collection here. That's an interesting question (and I've written a blog post about it, and had long conversations with the authors of various different sorted collection libs on PyPI), but it's not relevant here. If we wanted to add sorted collection ABCs to the stdlib, that still wouldn't help the OP at all, because things like list and OrderedDict are Ordered in his sense but not sorted in any useful sense.
(If you're curious: I think the best answer is to use add. A sorted collection is more like a multiset, at least from the mutation side, than like a list. Append, insert, and __setitem__ are all nonsense; add makes perfect sense. But not everyone agrees with me. If you want to discuss this, you should probably take it off-list, or start a new thread on adding sorted collections ABCs, because they have very little to do with adding an Ordered ABC.)
> Nevertheless, I don't think this shold be added to Python yet. I
> don't think your use case is a valid one for supporting it. I have
> two reasons:
>
> (1) In principle, record types should not be initialized with
> positional arguments. I experienced cogniztive dissonance as soon
> as I saw your __init__():
>
>> Here's how the current__init__ method of BasicStruct looks like:
>
>> class BasicStruct(object):
>> """Class for holding struct-like objects."""
>
> "with naturally-ordered slots" should be appended.
>
>> __slots__ = () # should be extended by deriving classes
>
>> def __init__(self, *args, **kwargs):
>
> Yes, we do it in C all the time, and it works fine[1] there. But
> the semantics are mismatched at the conceptual level, and it is
> error-prone in practice if the type has more than about 3 slots of
> differing types
It's worth noting that the C committee agrees with you, which is why they added designated initializers to the language, which are often considered among the best upgrades from C89. Unless you need C89 support or (portable) C++ compatibility (sadly, you usually do need one or the other…), unless you're initializing something with only a few attributes with an obvious-to-the-reader order (like a point, where it's pretty clear that { 1, 2, 3 } is initializing x, y, and z), you use a designated initializer like { .spam=1, .eggs=2, .cheese=3 }. Which looks sort of like Python, but with extra line noise.
> If a concrete BasicStruct "wants" to provide a
> positional constructor, it can use a factory function.
>
> Unfortunately this would be impossible to do automatically in the
> exactly the cases of interest -- you need the *source code* order
> of slots, but that's not available for introspection at runtime.
> So it would violate DRY. I don't consider that an argument for
> the proposal at the moment, but feel free to try to convince the
> list (and maybe me too<wink/>) otherwise.) (In fact I consider it
> the reverse: for Sequences, The Order You See Is The Order You
> Get, and the DRY violation occurs *because* you are using an
> inappropriate container for your purpose (ordered slots).
>
> (2) BasicStruct isn't the relevant use case: you can always just
> document that __slots__ is restricted to ordered finite iterables
It had better be a repeatable one too; after all, iter(['a', 'b']) is an ordered finite iterable, but not a very good candidate for slots. But that's a whole other thread. :)
Andrew Barnert writes:
> On Nov 6, 2015, at 21:00, Stephen J. Turnbull <ste...@xemacs.org> wrote:
> > This ABC would be a tar pit of recriminations between class authors
> > and class clients.
> I think you've missed the point of his proposal. It doesn't matter
> _what_ the order is
That's precisely what I see as problematic, unless the author of the
subclass is the same as the author of the code using the subclass.
> But, whether the proposal is useful or not, it is sufficiently
> specified.
I wrote inaccurately, I guess. My contention is that it's more
dangerous than useful as currently specified but that could be
reversed with additional restrictions.
> How would you define the comparison function for OrderedDict in a
> way that makes any semantic sense? Or, for that matter, list?
Again, bad nomenclature, sorry.[1] I should have used "index". For
this application, I have in mind
class Ordered:
def index(self, key):
return list(z for z in self).index(key)
def compare(self, key1, key2):
return self.index(key1) < self.index(key2)
as the default implementation (except that for Amir's application it's
.index() that's interesting, not .compare() -- .compare() could be
omitted I guess, fn. [1] applies). The problem with list would be
that it can have multiple entries of the same value that are not
adjacent, of course, but then it wouldn't work for Amir's application
anyway. This is part of what I have in mind when I say
"underspecified".
I don't think thought about how this collections.abc.Ordered should
interact with objects that could be considered to represent multisets.
Do you?
--
---
You received this message because you are subscribed to a topic in the Google Groups "python-ideas" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/python-ideas/B1Pt76OtJi8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to python-ideas...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Not very useful, sure—I argued that myself—but how is it dangerous? The only risk here is the risk that comes from adding more code, docs, and complexity to the stdlib.
>> How would you define the comparison function for OrderedDict in a
>> way that makes any semantic sense? Or, for that matter, list?
>
> Again, bad nomenclature, sorry.[1] I should have used "index". For
> this application, I have in mind
>
> class Ordered:
>
> def index(self, key):
> return list(z for z in self).index(key)
>
> def compare(self, key1, key2):
> return self.index(key1) < self.index(key2)
For, How is that at all useful? What code can you imagine that needs to compare elements from an arbitrary iterable, and would rather have a comparison that's linear in the length of the iterable than none at all?
Second, why list(z for z in self) instead of just list(self) or [z for z in self]? It seems like you're deliberately trying to find the slowest and least straightforward way of implementing it…
But, most importantly, if you want an index method, why aren't you just requiring Sequence, which has one? The notion of index implies the notion of random accessibility—which is exactly what Sequence adds on top of Sized Iterable Container.
Of course there are types for which compare might exist but index might not (e.g., a range of reals, or a set that's only partially ordered), but they're not iterables. (Well, a partially ordered set could Iterate in partially-arbitrary order, but then it's not Ordered in the OP's sense.)
His proposal really does specify exactly what he wants, it's dead simple, and it does all he asks of it. The only question is whether anyone needs it (and, even if they do, whether it needs to be in the stdlib).
> as the default implementation (except that for Amir's application it's
> .index() that's interesting, not .compare() -- .compare() could be
> omitted I guess, fn. [1] applies). The problem with list would be
> that it can have multiple entries of the same value that are not
> adjacent, of course, but then it wouldn't work for Amir's application
> anyway. This is part of what I have in mind when I say
> "underspecified".
Well, yes, what he _really_ requires here is an ordered, _unique_, finite, repeatable iterable. Adding a test for Ordered is clearly insufficient for that, and doesn't seem particularly useful. But again, that doesn't mean that Ordered is underspecified in any way; it just means he doesn't have a good use case for it.
> I don't think thought about how this collections.abc.Ordered should
> interact with objects that could be considered to represent multisets.
> Do you?
I'm not sure what you're asking here. But clearly list, OrderedCounter, and a SortedMultiSet type are all ordered, and can all be used to represent multisets in rather obvious ways. And the only way his proposed Ordered has to interact with them is that they all inherit from or get registered with the Ordered ABC (and aren't lying about it).
Of course your proposal for some kind of sorting-related ABC that generates the sort order from indexes would have a problem with multisets, and especially with list as you mentioned above, but that has nothing to do with his proposal.
>> Surely OrderedDict and list are perfectly reasonable types for
>> __slots__, despite the fact that their comparison function doesn't
>> exist.
>
> If given the above renaming you still say it doesn't exist, I don't
> understand what you're trying to say.
OK, they're perfectly reasonable types for __slots__, despite the fact that no useful, acceptably efficient, or in any way desirable comparison function exists. Better?
> Not very useful, sure—I argued that myself—but how is it
> dangerous? The only risk here is the risk that comes from adding
> more code, docs, and complexity to the stdlib.
This proposal requires that users not only read the docs in the
stdlib, but also the docs of each class, perhaps each object, using
the functionality. Asking users to read docs thoroughly is a recipe
for bugs, especially since the order used is likely to be documented
as "the natural order", and people will have different ideas about
that. This is the "complication" the Zen warns about, as well as
being "implicit". You may not consider that dangerous, but I do.
And on top of that, not only doesn't it provide any guarantees, you've
pretty much convinced me it's impossible to do so. If that's not an
attractive nuisance, what is?
> But, most importantly, if you want an index method, why aren't you
> just requiring Sequence, which has one?
Because "ordered sets" and "ordered dicts" aren't Sequences.
But don't ask me, ask the OP. As I wrote earlier, no use case for
set- or dict-valued __slots__ has been given. I have nothing invested
in anything I wrote except that. I'm happy to concede that everything
else I wrote was boneheaded, retract it, and apologize for wasting
your time.
--
---
You received this message because you are subscribed to a topic in the Google Groups "python-ideas" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/python-ideas/B1Pt76OtJi8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to python-ideas...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
_______________________________________________
Python-ideas mailing list
Python...@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/
I would like to expand on my original use case, which I hope will provide a more persuading argument.As part of BasicStruct I intend to allow the use of mapping types as __slots__, with the semantics of default values.So it'll look something like this:class Point(BasicStruct):__slots__ = {'x': 5, 'y': 7}
My fear is that someone will just use a dict literal as stated above and try to create an object with positional arguments:Point(0)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 classesdef __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 = Noneif 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.
I've maintained code that does this:
self.headers = OrderedDict(headers)
self.origheaders = len(headers)
… so it can later do this:
altheaders = list(self.headers.items())[self.origheaders:]
Not a great design, but one that exists in the wild, and would be broken by OrderedDict not allowing a dict as an argument.
Also, this wouldn't allow creating an OrderedDict from an empty dict (which seems far less stupid, but I didn't lead with it because I can't remember seeing it in real code).
I've been searching through GitHub for "ordered" and similar phrases.
Much of the usage is OrderedDict and OrderedSet, which really don't
benefit from an essentially redundant inheritance from a hypothetical
collections.Ordered. There are some tools that enable UI reordering,
and a bunch of tree- and graph-traversal ordering functions. Again,
not much benefit from a collections.Ordered.
However, Django has a class factory that creates an attribute `can_order`:
def formset_factory(form, formset=BaseFormSet, extra=1, can_order=False,
can_delete=False, max_num=None, validate_max=False,
min_num=None, validate_min=False):
"""Return a FormSet for the given form class."""
if min_num is None:
min_num = DEFAULT_MIN_NUM
if max_num is None:
max_num = DEFAULT_MAX_NUM
# hard limit on forms instantiated, to prevent memory-exhaustion attacks
# limit is simply max_num + DEFAULT_MAX_NUM (which is 2*DEFAULT_MAX_NUM
# if max_num is None in the first place)
absolute_max = max_num + DEFAULT_MAX_NUM
attrs = {'form': form, 'extra': extra,
'can_order': can_order, 'can_delete': can_delete,
'min_num': min_num, 'max_num': max_num,
'absolute_max': absolute_max, 'validate_min': validate_min,
'validate_max': validate_max}
return type(form.__name__ + str('FormSet'), (formset,), attrs)
This attribute gets set in several places, but checked only twice in
the Django codebase. Unfortunately, I think switching to the proposed
inheritance mechanism would make the code worse, not better:
`self.can_order` would become `isinstance(self, collections.Ordered)`.
The readability of the Django internal code would not be much
different, but users would lose consistency of introspectability as
the other features like `can_delete` are simple class attributes.
So if OrderedDict had always rejected construction from a dict, how would you have written this?
"[Python-ideas] OrderedCounter and OrderedDefaultDict"
https://mail.python.org/pipermail/python-ideas/2015-November/037163.html
- +2 for collections.ABC.Ordered
- exception on initialization w/ an unordered collection /// __init__force_from_unordered
On Nov 8, 2015 1:46 PM, "Guido van Rossum" <gu...@python.org> wrote:
>
> I'm warming up slightly to the idea of this ABC.
>
> I've re-read Amir's post, and if I found myself in his situation I would have used a combination of documenting that __slots__ needs to be ordered and at runtime only checking for a few common definitely-bad cases. E.g. for exactly set or dict (not subclasses, since OrderedDict inherits from dict) would cover most of the common mistakes: most people will use a literal in their __slots__ definition so we just need to watch out for the common literals. Those users who are sophisticated enough to use some advanced mapping type in their __slots__ should just be expected to deal with the consequences.
>
> But the Ordered ABC, while not essential (unless you're a perfectionist, in which case you're in the wrong language community anyways :-) still fills a niche.
I take issue with this comment because it's in the middle of the text.
It's more than a perfection thing:
- Ordered collections may already be Sorted [1]
- [ ] would collectiond.namedtuple [~struct w/ slots] also be Ordered
- [1] here's a rejected PR for jupyter/nbformat https://github.com/jupyter/nbformat/pull/30 "ENH: v4/nbjson.py: json.loads(object_pairs_hook=collections.OrderedDict)"
>
> The Ordered ABC should have no additional methods, and no default implementations. I think it should apply to collections but not to iterators. It should apply at the level of the read-only interface. Sequence is always Ordered. Mapping and Set are not by default, but can have it added. OrderedDict is the prime (maybe only) example -- it's a MutableMapping and Ordered. We might eventually get an OrderedSet.
>
> A sorted set or mapping (e.g. one implemented using some kind of tree) should also be considered Ordered, even though otherwise this is a totally different topic -- while some other languages or branches of math use "order" to refer to sorting (e.g. "partial ordering"), in Python we make a distinction: on the one hand there's sorted() and list.sort(), and on the other hand there's OrderedDict.
>
> So, I think that the Ordered ABC proposed here is totally well-defined and mildly useful. It may be somewhat confusing (because many people when they first encounter the term "ordered" they think it's about sorting -- witness some posts in this thread). The use cases are not very important. I guess I'm -0 on adding it -- if better use cases than Amir's are developed I might change to +0. (I don't care much about Serhiy's use cases.)
>
> Sorry for the rambling.
>
> --
> --Guido van Rossum (python.org/~guido)
>
Is there also a collections.Reversible? Either way, can you report that bug in the typehinting tracker on GitHub.
--Guido (mobile)
https://github.com/ambv/typehinting
--Guido (mobile)
> There is a precedent for declaring that a method isn't implemented:
> __hash__. The convention is to set it to None in the subclass that
> explicitly doesn't want to implement it.
Isn't ‘raise NotImplementedError’ the more explicit convention provided
by Python (as a built-in, explicitly-named exception!) for communicating
this meaning?
--
\ “[It's] best to confuse only one issue at a time.” —Brian W. |
`\ Kernighan, Dennis M. Ritchie, _The C programming language_, 1988 |
_o__) |
Ben Finney
> No, raising NotImplementedError means that a subclass was supposed to
> implement the method. In this case it's different -- it should appear
> as if the method isn't implemented to code that checks for the
> method's presence.
Understood, thanks for explaining the difference.
> Introspecting whether the code raises NotImplementedError is
> unfeasible. We explicitly decided that setting the method to None
> indicates that it should be considered as absent by code that checks
> for the method's presence.
Oh, you mean setting the attribute so it's not a method at all but a
simple non-callable object? That makes sense.
Why recommend ‘None’, though? We now have the ‘NotImplemented’ object;
why not set the attribute of the class as ‘foo = NotImplemented’?
--
\ “We are stuck with technology when what we really want is just |
`\ stuff that works.” —Douglas Adams |
Guido van Rossum <gu...@python.org> writes:
> No, raising NotImplementedError means that a subclass was supposed to
> implement the method. In this case it's different -- it should appear
> as if the method isn't implemented to code that checks for the
> method's presence.
Understood, thanks for explaining the difference.
> Introspecting whether the code raises NotImplementedError is
> unfeasible. We explicitly decided that setting the method to None
> indicates that it should be considered as absent by code that checks
> for the method's presence.
Oh, you mean setting the attribute so it's not a method at all but a
simple non-callable object? That makes sense.
Why recommend ‘None’, though? We now have the ‘NotImplemented’ object;
why not set the attribute of the class as ‘foo = NotImplemented’?
> On Sat, Dec 26, 2015 at 4:33 PM, Ben Finney <ben+p...@benfinney.id.au>
> wrote:
>
> > Why recommend ‘None’, though? We now have the ‘NotImplemented’
> > object; why not set the attribute of the class as ‘foo =
> > NotImplemented’?
>
> Too late by many language releases, and not worth fixing.
Yes, to be clear I'm not suggesting a change of ‘__hash__ = None’.
I am talking of new code, like the changes being discussed in this
thread: since we have ‘NotImplemented’ now, we can more explicitly
indicate not-implemented attributes with ‘foo = NotImplemented’.
> Either way it's an arbitrary token that you would have to check for
> specially and whose meaning you'd have to look up. Also,
> NotImplemented has very special semantics (its main use is for
> *binary* operators to indicate "not overloaded on this argument, try
> the other") -- this has nothing to do with that.
Okay, that's clear. Semantics can change over time, though, and I think
‘NotImplemented’ much more clearly indicates the desired semantics than
‘None’, and is not ambiguous with existing uses of ‘foo = None’ on a
class.
So I advocate a class-level ‘foo = NotImplemented’ as an obvious way to
indicate an expected method is not implemented on this class.
Thanks for discussing and explaining. My vote counts for whatever it
counts for, and I'll let these arguments stand or fall as I've presented
them.
--
\ “Every sentence I utter must be understood not as an |
`\ affirmation, but as a question.” —Niels Bohr |
* collections.abc.Ordered
* collections.abc.Reversible
* collections.abc.Infinite [...]
* collections.abc.Sorted ?
* collections.abc.Ordered
* collections.abc.Reversible
* collections.abc.Infinite [...]
* collections.abc.Sorted ?
* collections.abc.Recursive ?
Rationale:
These are all attributes of collections that would allow us to reason about [complexity, types, runtime]?
[While someone is at it, annotating functions and methods with complexity class URI fragments accessible at runtime could also be useful for [dynamic programming].]
* Ordered is justified by this thread
* Reversible is distinct from Ordered (because Infinite sequences)
* Infinite is the distinction between Ordered and Reversible
* collections.abc.Sorted would be a useful property to keep track of (because then you don't have to do element-wise comparisons for each collection member)
...
* collections.abc.Recursive could also be a useful property to mixin [again for dynamic programming]
https://en.wikipedia.org/wiki/Dynamic_programming
On Dec 26, 2015 8:11 PM, "Wes Turner" <wes.t...@gmail.com> wrote:
>
> * collections.abc.Ordered
> * collections.abc.Reversible
> * collections.abc.Infinite [...]
>
> * collections.abc.Sorted ?
> * collections.abc.Recursive ?
>
> Rationale:
>
> These are all attributes of collections that would allow us to reason about [complexity, types, runtime]?
>
> [While someone is at it, annotating functions and methods with complexity class URI fragments accessible at runtime could also be useful for [dynamic programming].]
>
> * Ordered is justified by this thread
> * Reversible is distinct from Ordered (because Infinite sequences)
> * Infinite is the distinction between Ordered and Reversible
>
> * collections.abc.Sorted would be a useful property to keep track of (because then you don't have to do element-wise comparisons for each collection member)
>
> ...
>
> * collections.abc.Recursive could also be a useful property to mixin [again for dynamic programming]
>
> https://en.wikipedia.org/wiki/Dynamic_programming
https://en.wikipedia.org/wiki/Goal_programming
There are more properties of sequences listed here; IDK if this is out of scope for OT: https://en.wikipedia.org/wiki/Sequence#Formal_definition_and_basic_properties
Vague use case: algorithmic selection / unhalting-avoidance with combinatorial data/logic sequences. [e.g. find the fastest halting solution]
Practically, Ordered is a property of various types [e.g. is this a poset or not]. There is currently no way to check for .ordered with hasattr.
These properties are things we currently keep in mind (some of our 7±2 things) and haven't yet figured out how to annotate with and access at runtime.
On 27.12.15 01:05, Guido van Rossum wrote:
There is a precedent for declaring that a method isn't implemented:
__hash__. The convention is to set it to None in the subclass that
explicitly doesn't want to implement it. The __subclasshook__ in
collections.Hashable checks for this. The pattern is also used for
__await__.
Yes, this was the first thing that I tried, but it doesn't work, as shown in my example in issue25864. This is yet one thing that should be fixed in Reversible.
May be we have to use this idiom more widely, and specially handle assigning special methods to None. The error message "'sometype' can't be reverted" looks better than "'NoneType' is not callable".
I was trying to recall if we'd ever seriously considered
NotImplemented for this use case, but as near as I can tell, the
"__hash__ = None" approach was born as the obvious Python level
counterpart of setting the C level tp_hash slot to NULL in Python 3.0:
https://hg.python.org/cpython/rev/c6d9fa81f20f/
We then retained the "__hash__ = None" behaviour at the Python level
even after switching to a custom slot entry at the C level as part of
resolving some corner cases that were found when backporting the abc
module from Python 3.0 to 2.6:
https://bugs.python.org/issue2235#msg69324
So this is a case of C's NULL pointer concept being visible in
Python's semantic model as "attribute = None". Operand coercion is
actually the special case on that front, as "None" needs to be
permitted as a possible result, and exceptions can't be used as an
alternative signalling channel due to the runtime cost involved.
Cheers,
Nick.
--
Nick Coghlan | ncog...@gmail.com | Brisbane, Australia