[Python-Dev] Re: Comparing dict.values()

2019-07-24 Thread Steven D'Aprano
On Tue, Jul 23, 2019 at 10:02:34PM -0400, Terry Reedy wrote:

[...]
> If one has not learned the default meaning of '==' in Python.  Perhaps 
> this should be given more emphasis in beginner courses.  "What does it 
> mean for two object to be 'equal'?"  It is not a trivial question.

No, it is not trivial, but the default meaning of equality in Python 
does not match the common idea that two things are equal if they are the 
same, equivalent, interchangeable, etc. By default, no two objects are 
ever equal, even if their values are equal. Equality only holds between 
an object and itself.

(In fairness, it is hard to think of another, more useful, definition of 
equality suitable as the default.)

In any case, the default semantics of equality inherited from object may 
explain the current behaviour, but that doesn't mean that the current 
behaviour is useful. When it is meaningful to say that "the value of 
these two distinct objects are equal", that is a strong hint that 
equality ought to be based on the value, rather than the identity, of 
the objects.


[...]
> Makes sense, up to here.

I'm glad to hear it, because I think that's a strong invariate: if the 
items are equal, so should the values be equal.

Beyond that, I'm not certain what is the right behaviour.



> >  # Fall back on value by value comparison?
> >  return list(self) == list(other)
> 
> This seems wrong.  Creating two lists raises the cost and the comparison 
> will depend on insertion order.

You're probably right. I did say that this was potentially expensive. We 
should be able to avoid the needless creation of two lists:

return all(x==y for x, y in zip(self, other))

but that still leaves the insertion order problem.

How does this seem to you? Two dict.values objects are equal if:

- they are in fact the same object (identity test on the views);

- they are both views of the same dict (identity test on the dicts);

- they are views of distinct, but equal, dicts;

- or there is a 1:1 correspondence between values (possibly not 
  unique) in the two views.


The first three tests should be straight-forward. The last is likely be 
slow, but something like this ought to work:

a = list(self)
b = list(other)
return len(a) == len(b) and all(a.count(x) == b.count(x) for x in a)


Given that we cannot rely on the values being hashable or even sortable, 
I don't know how to make it more efficient in the general case.



-- 
Steven
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/JD74V5OSJDY7BHJWLXVD5NKQ5EP75EGL/


[Python-Dev] Re: Comparing dict.values()

2019-07-24 Thread Ronald Oussoren via Python-Dev


Op 24 jul. 2019 om 02:27 heeft Steven D'Aprano  het 
volgende geschreven:

> But I can suggest at least one useful invariant. If a, b are two dicts:
> 
>a.items() == b.items()
> 
> ought to be equivalent to:
> 
>(a.keys() == b.keys()) and (a.values() == b.values)

I don’t think this invariant holds unless comparison is order dependent.  {1:2, 
3:4} and {1:4, 3:2} have the same keys and values, but not the same items.  

Ronald
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/TRAL2TDEXGOWBSISTU3CCL6BCAXK4CVN/


[Python-Dev] Re: Comparing dict.values()

2019-07-24 Thread Rob Cliffe via Python-Dev




On 24/07/2019 10:31:46, Steven D'Aprano wrote:


How does this seem to you? Two dict.values objects are equal if:

- they are in fact the same object (identity test on the views);

- they are both views of the same dict (identity test on the dicts);

- they are views of distinct, but equal, dicts;

Naive question: Is there a way (in Python) to get at the underlying dict 
from a dict.values object,

or more generally from any dict view object?

>>> dir({}.values())
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', 
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '
__init__', '__init_subclass__', '__iter__', '__le__', '__len__', 
'__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '

__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

Rob Cliffe
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/NZDVGFXMTUDW5ZSTAAMWFDLUEFLWGEGG/


[Python-Dev] Re: Comparing dict.values()

2019-07-24 Thread Serhiy Storchaka

24.07.19 13:33, Rob Cliffe via Python-Dev пише:
Naive question: Is there a way (in Python) to get at the underlying dict 
from a dict.values object,

or more generally from any dict view object?


No, there is not. As well as there is no way to get at the underlying 
list, tuple, dict from corresponding iterators.

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/GQS5KVH36SHGTIRQZ63IGNCTZ6KESQXR/


[Python-Dev] Re: Comparing dict.values()

2019-07-24 Thread Antoine Pitrou
On Tue, 23 Jul 2019 23:44:35 +0100
MRAB  wrote:
> 
> However, when comparing the values you have a problem: you have 2 
> collections of objects that might contain duplicates, might not be 
> hashable, and might not be sortable, so comparing them could be 
> inefficient, and you can't refer back to their keys like in the case of 
> comparing the items as above because the 2 dicts might have different 
> keys. Unless someone can come up with an efficient solution, I'd 
> probably go with raising an exception.

Equality comparisons should never raise.

Regards

Antoine.

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/KNYYAVFME5ADN4UKMEW2TNHHZ4BGPSXG/


[Python-Dev] Re: What is a public API?

2019-07-24 Thread Brett Cannon
Barry Warsaw wrote:
> On Jul 23, 2019, at 12:02, Steve Dower steve.do...@python.org wrote:
> > Even if the performance impact is zero, commits that
> > span the entire codebase for not-very-impactful changes have a negative 
> > impact on
> > readability (for example, someone will suddenly become responsible for 
> > every single module
> > as far as some blame tools are concerned - including github's suggested 
> > reviewers). I'm
> > inclined to think this one would be primarily negative.
> > If we were to adopt @public, its inclusion in the stdlib would follow the
> precedence we already have for non-functional changes (e.g. whitespace, code 
> cleanup,
> etc.).  It definitely shouldn’t be done willy nilly but if the opportunity 
> arises, e.g.
> because someone is already fixing bugs or modernizing a module, then it would 
> be fair game
> to add @public decorators.  Of course, you can’t do that if it’s not 
> available. :)
> > We already maintain separate documentation from the
> > source code, and this is the canonical reference for what is public or not. 
> > Until we make
> > a new policy for __all__ to be the canonical reference, touching every file 
> > to use it is
> > premature (let alone adding a builtin).
> > Agreed, sort of.  We’ve had lots of cases of grey areas though, where the
> documentation doesn’t match the source. The question always becomes whether 
> the source or
> the documentation is the source of truth.  For any individual case, we don’t 
> always come
> down on the same side of that question.
> > So I apologise for mentioning that people care about
> > import performance. Let's ignore them/that issue for now and worry instead 
> > about making
> > sure people (including us!) know what the canonical reference for 
> > public/internal is.
> > +1

Since this is for the stdlib, then PEP 8 would be the place to spell out how to 
denote public/private appropriately.
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/Z7JMM7BB2YDP4FPU4WSLASCNQG2TXWR4/


[Python-Dev] Re: Comparing dict.values()

2019-07-24 Thread Brett Cannon
Serhiy Storchaka wrote:
> 23.07.19 23:59, Kristian Klette пише:
> > During the sprints after EuroPython, I made an
> > attempt at adding support for
> > comparing the results from .values() of two dicts.
> > Currently the following works as expected:
> > d = {'a': 1234}
> > 
> > d.keys() == d.keys()
> > d.items() == d.items()
> > 
> > but d.values() == d.values() does not return the expected
> > results. It always returns False. The symmetry is a bit off.
> > Is it expected to you that iter(d) == iter(d) returns False?
> By default the equality operator returns True when and only when 
> operands are identical. It is expected. Some objects (like numbers or 
> strings) can override the default behavior and implement different rules 
> for equality.
> > I'd argue that Python should compare the values as
> > expected here,
> > or if we don't want to encourage that behaviour, maybe we should
> > consider raising an exception.
> > Returning just False seems a bit misleading.
> > What the rule for equality do you propose? What is the use case for it?
> If you want to compare dict value views as ordered sequences, it can be 
> surprised that d1.values() != d2.values() when d1 == d2. It will
> be 
> inconsistent with orderless comparison of keys() and items(). If
> you 
> want to compare them as unordered sequences, the computation complexity 
> of the operation will be quadratic.
> Note also, that while in Python 2 always d.values() == d.values(), it 
> is possible that d1.keys() != d2.keys() and d1.values() != 
> d2.values() when d1 == d2. Python 3 is more consistent.

When I saw this I thought, "it should be like `set(d1.values()) == 
set(d2.values())`", but has been pointed out there's no guarantee that all 
values will be hashable. After that I have no expectation since order isn't 
guaranteed.

I think this is one of those cases where it's superficially surprising when you 
don't think about all the ramifications, but once you understand the complexity 
of the problem then it becomes more clear that it isn't straight-forward.

To me a doc update for dict.values() stating that the iterator can't be 
compared and a brief mention as to why would be the best solution for this.
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/PIFGKWEXP2LFEPCJJLVJAXIL3YCKVYCT/


[Python-Dev] Re: Comparing dict.values()

2019-07-24 Thread Eric V. Smith

On 7/24/2019 1:30 PM, Brett Cannon wrote:

Serhiy Storchaka wrote:


o you propose? What is the use case for it?
If you want to compare dict value views as ordered sequences, it can be
surprised that d1.values() != d2.values() when d1 == d2. It will
be
inconsistent with orderless comparison of keys() and items(). If
you
want to compare them as unordered sequences, the computation complexity
of the operation will be quadratic.
Note also, that while in Python 2 always d.values() == d.values(), it
is possible that d1.keys() != d2.keys() and d1.values() !=
d2.values() when d1 == d2. Python 3 is more consistent.
When I saw this I thought, "it should be like `set(d1.values()) == 
set(d2.values())`", but has been pointed out there's no guarantee that 
all values will be hashable. After that I have no expectation since 
order isn't guaranteed.


I think this is one of those cases where it's superficially surprising 
when you don't think about all the ramifications, but once you 
understand the complexity of the problem then it becomes more clear 
that it isn't straight-forward.


To me a doc update for dict.values() stating that the iterator can't 
be compared and a brief mention as to why would be the best solution 
for this.


(I hope my quoting is correct.)

I agree with Brett: let's just document this and not make any code changes.

If someone really has a use case, which I haven't seen, then they can 
write their own comparison using constraints specific to their data: 
perhaps their values are hashable, for example.


Eric

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/C774AG3OQRG6XCZ4JKVP6UYDX6DELMQR/


[Python-Dev] Re: Comparing dict.values()

2019-07-24 Thread Steven D'Aprano
On Wed, Jul 24, 2019 at 05:30:19PM -, Brett Cannon wrote:

> When I saw this I thought, "it should be like `set(d1.values()) == 
> set(d2.values())`", but has been pointed out there's no guarantee that 
> all values will be hashable.

The hashability requirement for sets is, in a sense, an implementation 
detail. It might be a requirement for sets in Python the language, 
but its not a requirement for abstract "sets of values".

E.g. Java includes a standard TreeSet which doesn't require hashability

https://docs.oracle.com/javase/7/docs/api/java/util/TreeSet.html

In this case, they need to be multisets, since 

{'a': 1, 'b': 2, 'c': 1}.values() != {'a': 1, 'b': 2, 'c': 2}.values()


> After that I have no expectation since order isn't guaranteed.
> 
> I think this is one of those cases where it's superficially surprising 
> when you don't think about all the ramifications, but once you 
> understand the complexity of the problem then it becomes more clear 
> that it isn't straight-forward.

Nobody said it was straight-forward, particularly if we want guaranteed 
efficient comparisons in both time and space at the same time.

Brett, I feel that you are dismissing this thread as "not thinking 
through the ramifications" without reading it through, because I'm 
pretty sure that we have thought through the ramifications in a lot more 
detail than your dismissal justifies.

Let's start with the minimal change we have suggested: that two views 
should be considered equal if they both belong to the same dict.

assert d.values() == d.values()

Currently that assertion fails. Should it? Putting aside the convenience 
of "do nothing, just inherit the object.__eq__ behaviour" do you think 
that the current behaviour is *correct*?

(By correct I mean in the technical sense that if we were writing a 
functional spec for views, we would actively desire two views of the 
same dict to be unequal.)


> To me a doc update for dict.values() stating that the iterator can't 
> be compared and a brief mention as to why would be the best solution 
> for this.

We're not talking about comparing iterators. We're talking about 
comparing views into a dict. That's a difference that makes all the 
difference.



-- 
Steven
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/UPFBDHOHFSFLDF5KO3QZE6RH3C2GXE6B/


[Python-Dev] Re: Comparing dict.values()

2019-07-24 Thread Greg Ewing

Steven D'Aprano wrote:
Currently that assertion fails. Should it? Putting aside the convenience 
of "do nothing, just inherit the object.__eq__ behaviour" do you think 
that the current behaviour is *correct*?


What I'm getting from this thread is that there are a variety of
possible behaviours for dict values comparison, any of which could
be considered "correct" depending on what the programmer is trying
to do.

I know there are good reasons for the guideline that equality
comparisons should never raise exceptions, but this seems like a
situation where Python really should slap you on the ear and
make you specify exactly what you want.

--
Greg
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/WR2JGENQBL3EQ6ZUUFF2BPMMFTFDEH3R/


[Python-Dev] Re: Comparing dict.values()

2019-07-24 Thread David Mertz
I agree with Greg.

There are various possible behaviors that might make sense, but having
`d.values() != d.values()` is about the only one I can see no sense in.

This really feels like a good cade for reading a descriptive exception. If
someone wants too compare `set(d.values())` that's great. If they want
`list(d.values())`, also a sensible question. But the programmer should
spell it explicitly.

This feels similar to NumPy arrays, that also will not compare for equality
in bare form. But they offer .any(), and .all() and other means of
expressing the comparison you actually want in a situation.

On Wed, Jul 24, 2019, 6:32 PM Greg Ewing 
wrote:

> Steven D'Aprano wrote:
> > Currently that assertion fails. Should it? Putting aside the convenience
> > of "do nothing, just inherit the object.__eq__ behaviour" do you think
> > that the current behaviour is *correct*?
>
> What I'm getting from this thread is that there are a variety of
> possible behaviours for dict values comparison, any of which could
> be considered "correct" depending on what the programmer is trying
> to do.
>
> I know there are good reasons for the guideline that equality
> comparisons should never raise exceptions, but this seems like a
> situation where Python really should slap you on the ear and
> make you specify exactly what you want.
>
> --
> Greg
> ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/WR2JGENQBL3EQ6ZUUFF2BPMMFTFDEH3R/
>
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/ROEAXSGAQOAOCTI7WL57FO23DDXSPN4E/


[Python-Dev] Re: Comparing dict.values()

2019-07-24 Thread Rob Cliffe via Python-Dev




On 25/07/2019 00:09:37, David Mertz wrote:

I agree with Greg.

There are various possible behaviors that might make sense, but having 
`d.values() != d.values()` is about the only one I can see no sense in.

+1


This really feels like a good cade for reading a descriptive 
exception. If someone wants too compare `set(d.values())` that's 
great. If they want `list(d.values())`, also a sensible question. But 
the programmer should spell it explicitly.



So, a helpful error message including something like "Cannot compare 
dict.values directly, consider converting to sets / lists / sorted lists 
before comparing" ?

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/CSTSLCDEJYKDLADQV5PJRCSSVTMB5RIG/


[Python-Dev] Re: Comparing dict.values()

2019-07-24 Thread David Mertz
Exactly! that was my thought that the exception message could hint at
likely approaches. The NumPy example seems to have a good pattern:

arr1 == arr2

ValueError: The truth value of an array with more than one element is
ambiguous.

Use a.any() or a.all().


On Wed, Jul 24, 2019, 8:06 PM Rob Cliffe via Python-Dev <
python-dev@python.org> wrote:

>
>
> On 25/07/2019 00:09:37, David Mertz wrote:
> > I agree with Greg.
> >
> > There are various possible behaviors that might make sense, but having
> > `d.values() != d.values()` is about the only one I can see no sense in.
> +1
> >
> > This really feels like a good cade for reading a descriptive
> > exception. If someone wants too compare `set(d.values())` that's
> > great. If they want `list(d.values())`, also a sensible question. But
> > the programmer should spell it explicitly.
> >
> >
> So, a helpful error message including something like "Cannot compare
> dict.values directly, consider converting to sets / lists / sorted lists
> before comparing" ?
> ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/CSTSLCDEJYKDLADQV5PJRCSSVTMB5RIG/
>
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/2IMLY36A6K45LHCXO2OVQJZBQKL47U6T/


[Python-Dev] Re: Comparing dict.values()

2019-07-24 Thread Rob Cliffe via Python-Dev
I considered an alternative: return True if the underlying dicts were 
identical or equal, and raise an Exception otherwise.
But I soon decided that this was a terrible idea: it could hide a bug by 
making faulty code work intermittently.
Apologies for doubtless belabouring the blindingly obvious (but then 
again, if I don't mention this possibility, maybe someone even more 
idiotic than me will suggest it ).


On 25/07/2019 00:49:56, Rob Cliffe via Python-Dev wrote:



On 25/07/2019 00:09:37, David Mertz wrote:

I agree with Greg.

There are various possible behaviors that might make sense, but 
having `d.values() != d.values()` is about the only one I can see no 
sense in.

+1


This really feels like a good cade for reading a descriptive 
exception. If someone wants too compare `set(d.values())` that's 
great. If they want `list(d.values())`, also a sensible question. But 
the programmer should spell it explicitly.



So, a helpful error message including something like "Cannot compare 
dict.values directly, consider converting to sets / lists / sorted 
lists before comparing" ?

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/CSTSLCDEJYKDLADQV5PJRCSSVTMB5RIG/


---
This email has been checked for viruses by AVG.
https://www.avg.com



___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/5K4EP5AKR5XPGJ5657RCHRTS6QVSJVWE/