News for hackers. Stuff that matters.
Re:Migrating to Python 3 with pleasure by AlexCoventry on Sunday February 04, 2018 @06:19PM (#16305525)
I've moved to python 3 over the past couple of months, after resisting for the better part of a decade. I like it.

One surprising thing I learned from this document is that dicts now iterate in assignment order, not hash order. That's going to break some code for people.

Re:Migrating to Python 3 with pleasure by StavrosK on Sunday February 04, 2018 @06:20PM (#16305537)
Dicts never had an iteration order, though. If you relied on dicts iterating in order, you were kind of asking for it.
Re:Migrating to Python 3 with pleasure by jstimpfle on Sunday February 04, 2018 @06:26PM (#16305557)
I believe newer Python versions have at least deterministic iteration order (correct me if I'm wrong), while some previous ones had a non-deterministic one (non-deterministic between mutiple invocations of the interpreter). But there is also OrderedDict which iterates in assignment order.
Re:Migrating to Python 3 with pleasure by StavrosK on Sunday February 04, 2018 @06:32PM (#16305571)
No, you're right. I believe dict orders were made deterministic (by insertion order) in 3.6. Before that, it was undefined.
Re:Migrating to Python 3 with pleasure by ubernostrum on Monday February 05, 2018 @01:26AM (#16307007)
In Python 2.7 prior to 2.7.3, or Python 3 prior to 3.3, iterating a dictionary would -- if it always contained the same set of keys -- be in a consistent order across multiple runs of the same program. This was an implementation detail not to be relied on.

Starting in 2.7.3 and 3.3, the hashing algorithm applied a per-process random salt to certain built-in types, in order to mitigate a potential denial-of-service vector by crafting dictionary keys which cause hash collisions. Unless the PYTHONHASHSEED environment variable was set to a consistent value, iteration over a dictionary was no longer accidentally consistent across runs.

In 3.6, the dictionary implementation was rewritten to drastically improve performance. As a side effect, dictionary iteration became consistent again, this time determined by insertion order. In 3.6, this consistency was an implementation detail and not to be relied on.

Beginning with 3.7, dictionary iteration order is finally guaranteed by the language, independent of implementation, and goes by insertion order.

Re:Migrating to Python 3 with pleasure by rtpg on Sunday February 04, 2018 @07:02PM (#16305666)
CPython interates in this fashion since 3.6, but it is not part of the Python spec.

Might be a bit contentious but it's not supposed to be relied upon

Re:Migrating to Python 3 with pleasure by thijsvandien on Sunday February 04, 2018 @07:14PM (#16305704)
It was recently decided that as of 3.7 it will be.

(Source: https://mail.python.org/pipermail/python-dev/2017-December/1...)

Re:Migrating to Python 3 with pleasure by dbcurtis on Sunday February 04, 2018 @11:40PM (#16306635)
Hmmmmmm.... that makes it hard for other implementations. CPython isn't the whole of the Python world. Requirements like that can be problematic for implementations like Micropython, for instance.
Re:Migrating to Python 3 with pleasure by sametmax on Monday February 05, 2018 @01:25AM (#16307003)
They asked people from the Jython, pypy and uPython community if it was ok before doing so.
Re:Migrating to Python 3 with pleasure by jsmeaton on Monday February 05, 2018 @12:04AM (#16306719)
The entire reason they decided to make it a standard rather than keep it as an implementation detail is to make things better for users. It’s not about just looking after cpython.
Re:Migrating to Python 3 with pleasure by lozenge on Monday February 05, 2018 @04:41AM (#16307715)
I suspect the reasoning was with CPython dominating, people would eventually make this assumption in their code, perhaps unintentionally, and reduce compatibility. Better to make it official.
Re:Migrating to Python 3 with pleasure by crdoconnor on Monday February 05, 2018 @04:50AM (#16307754)
The headache that having non-deterministic code causes more than makes up for that.

Among other things this makes writing tests much easier.

Re:Migrating to Python 3 with pleasure by fastball on Monday February 05, 2018 @06:47AM (#16308209)
Python dicts have always been touted as an unordered data structure though, so yeah, if you're depending on any type of order you shouldn't be.
Re:Migrating to Python 3 with pleasure by sethgecko on Monday February 05, 2018 @05:03AM (#16307811)
In 3.6 dicts are ordered (by insert order) as an implementation detail. From 3.7 on it will be a feature.
Re:Migrating to Python 3 with pleasure by vonseel on Sunday February 04, 2018 @09:51PM (#16306293)
There’s a well known YouTube video which covers all this comprehensively.

Raymond Hettinger, Modern Python Dictionaries... hopefully this is the correct one. https://youtu.be/npw4s1QTmPg

Re:Migrating to Python 3 with pleasure by kqr on Monday February 05, 2018 @01:31AM (#16307019)
Ooh, I'm no longer involved in the Python world but I love presentations by Hettinger. Thanks!
Re:Migrating to Python 3 with pleasure by ATsch on Sunday February 04, 2018 @08:25PM (#16305986)
EDIT: I was just informed it is as of 3.7 an official language feature, making everything below invalid

Personally, I'm worried people will come to rely on the new behaviour in code instead. As core developers have repeatedly said, dict order is still an implementation detail, it should not be relied on as it is not officially part of the language. Other implementations (except pypy) will probably not have this behaviour.

Yet, I feel like this will fall on deaf ears and become a de-facto part of the language. Blogs will state it as a new feature, Python books will teach it and new coders will rely on it, forever locking the dict internals in place for all python interpreters.

(If you need to rely on ordering, use an OrderedDict instead.)

Re:Migrating to Python 3 with pleasure by VHRanger on Sunday February 04, 2018 @06:34PM (#16305578)
Dicts are UNORDERED associative containers. If youre depending your app on implementation defined behavior, that's on your developpers shoulders. Stuff like that shouldn't pass code review
Re:Migrating to Python 3 with pleasure by jstimpfle on Sunday February 04, 2018 @06:42PM (#16305607)
It is surprising though that the order was non-deterministic, not only undefined. Determinism is something I intuitively expect from read-only operations like iteration.
Re:Migrating to Python 3 with pleasure by fyi1183 on Sunday February 04, 2018 @07:27PM (#16305759)
Non-determinism comes from randomness in the hash function. I don't know the details of the Python implementation, but generally you want randomness at the very least when processing potentially hostile user input. Otherwise your code is susceptible to a denial of service attack where the attacker sends data that was crafted to maximize hash collisions, to break the expected performance of hash tables.

From a theoretical angle, the only way to build hash tables with some kind of provable runtime guarantees is to include randomness.

Re:Migrating to Python 3 with pleasure by StavrosK on Sunday February 04, 2018 @07:38PM (#16305792)
I think that's a habit you need to shake. If something is undefined, you should intuitively shy away from expecting things from it. If I found myself wondering why some undefined behavior was not consistent, I'd question why I even believed it should be consistent in the first place.
Re:Migrating to Python 3 with pleasure by ridiculous_fish on Sunday February 04, 2018 @09:44PM (#16306266)
Would you expect that `str(some_dict) == str(some_dict)`?
Re:Migrating to Python 3 with pleasure by PeterisP on Monday February 05, 2018 @03:34AM (#16307454)
For that exact line I might expect that the result is true but still consider that line as "smelly" and meaningless, since dict equality cannot be compared by comparing their string representation.

I'd expect that any two ways of forming a dict with exactly same contents can result in different str(x) representation, and also that serializing and deserializing a dict can result in a different string representation.

Re:Migrating to Python 3 with pleasure by StavrosK on Monday February 05, 2018 @03:12AM (#16307368)
No, of course not. Some order has to be applied to serialize it to a string, but that order is not defined between calls.
Re:Migrating to Python 3 with pleasure by eesmith on Monday February 05, 2018 @03:31AM (#16307444)
Python long ago made the guarantee that:

> Keys and values are iterated over in an arbitrary order which is non-random, varies across Python implementations, and depends on the dictionary’s history of insertions and deletions. If keys, values and items views are iterated over with no intervening modifications to the dictionary, the order of items will directly correspond.

That is, the order will be maintained between calls, so long as the dictionary had not been modified.

Going back to "str(some_dict) == str(some_dict)". I would not expect to always be the same, but for entirely different reasons. Consider:

  class Strange():
    def __repr__(self):
      import random
      return str(random.random())

  some_dict = {1: Strange()}

  >>> str(some_dict) == str(some_dict)
  False
Re:Migrating to Python 3 with pleasure by StavrosK on Monday February 05, 2018 @03:44AM (#16307499)
A section called "CPython implementation detail" looks like the very antithesis of a guarantee, to me.
Re:Migrating to Python 3 with pleasure by eesmith on Monday February 05, 2018 @03:51AM (#16307529)
My apologies. I looked for the answer I knew was there, and quoted the wrong section because it matched what I was looking for.

I should have quoted the next section:

> If items(), keys(), values(), iteritems(), iterkeys(), and itervalues() are called with no intervening modifications to the dictionary, the lists will directly correspond.

Curiously, the "Dictionary view objects" section at https://docs.python.org/2.7/library/stdtypes.html#dictionary... has the same "Keys and values are iterated over in an arbitrary order which is non-random ..." text, but without being inside of a "CPython implementation detail" box.

Re:Migrating to Python 3 with pleasure by StavrosK on Monday February 05, 2018 @04:53AM (#16307766)
Huh, that's inconsistent. I guess they changed it to avoid the security problem and forgot to change the docs? Or maybe they didn't update 2.7 at all and it still behaves that way.
Re:Migrating to Python 3 with pleasure by ubernostrum on Monday February 05, 2018 @01:27AM (#16307011)
See this comment for the details:

https://news.ycombinator.com/item?id=16307007

Re:Migrating to Python 3 with pleasure by brett40324 on Sunday February 04, 2018 @07:30PM (#16305770)
It is simply that a python dict is not a list (read array).
Re:Migrating to Python 3 with pleasure by djrobstep on Sunday February 04, 2018 @06:44PM (#16305614)
Not for much longer, as of 3.7 the ordering is a language feature: https://mail.python.org/pipermail/python-dev/2017-December/1...

It's mad that it ever wasn't this way. Mapping-with-ordered-keys is such a useful and pervasive data structure (all database query result rows, for one) that an ordered dictionary should be a fundamental part of a language.

It has been so much more pleasant to write python since ordering was maintained by default.

Re:Migrating to Python 3 with pleasure by amyjess on Sunday February 04, 2018 @10:44PM (#16306454)
> Mapping-with-ordered-keys is such a useful and pervasive data structure (all database query result rows, for one) that an ordered dictionary should be a fundamental part of a language.

Here's one real-life use case of that: Avro records. One of the formats Avro uses is a text format that's basically ordered JSON. One company I worked for years ago used Avro as its wire protocol, and some Avro data was stored as JSON files on disk. Of course, Python's JSON implementation by default loads/unloads JSON to/from a dict. So just calling json.load() and json.dump() means I can't just load an Avro record from disk, change some data, and save it (which is something that came up when I was writing an upgrade script at a company I was working at years ago).

Thankfully, I had an out: the JSON library lets you override what container you load JSON into with object_pairs_hook, so I could just snarf it into an OrderedDict. But if I ever have to do this again after 3.7 comes out, I'm glad I won't have to worry about making sure I have the right container class. It makes my code simpler, and I won't have to leave a comment explaining why the code will break unless I specify an OrderedDict.

Re:Migrating to Python 3 with pleasure by djrobstep on Monday February 05, 2018 @12:08AM (#16306734)
Great example.

I hate to think of all the developer hours wasted because JSON doesn't maintain key ordering.

Re:Migrating to Python 3 with pleasure by fyi1183 on Monday February 05, 2018 @04:12AM (#16307605)
Not to mention the lost opportunities for delta compression.
Re:Migrating to Python 3 with pleasure by Avshalom on Sunday February 04, 2018 @07:39PM (#16305807)
>>(all database query result rows, for one)

What? No. SQL does not return results in any consistent ordering unless specifically instructed to.

Re:Migrating to Python 3 with pleasure by djrobstep on Sunday February 04, 2018 @08:11PM (#16305924)
Not the result set, the rows of the result set.
Re:Migrating to Python 3 with pleasure by jsjohnst on Sunday February 04, 2018 @10:26PM (#16306393)
Do you mean the columns of the row?
Re:Migrating to Python 3 with pleasure by djrobstep on Sunday February 04, 2018 @11:35PM (#16306622)
No, I mean the rows. Each row is semantically an ordered mapping.
Re:Migrating to Python 3 with pleasure by jsjohnst on Monday February 05, 2018 @08:09AM (#16308515)
Shouldn’t the collection of rows be a set or list, not a dictionary?

That said, you disagreed with my question then went on to show my question was on point.

The “rows themself” being an ordered map means you are referring to the columns, the order being set by the SELECT clause or table definition order (in case of wildcard).

That said, I personally feel iterating over table columns in that way to be a “bad code smell”. Not saying it’s bad in all cases, but generally it’s an anti-pattern to me.

Re:Migrating to Python 3 with pleasure by empthought on Monday February 05, 2018 @10:59AM (#16309571)
Order-significance is exactly how the relational model was defined in the beginning

"An array which represents an n-ary relation R has the following properties:

1. Each row represents an n-tuple of R.

2. The ordering of rows is immaterial.

3. All rows are distinct.

4. The ordering of columns is significant -- it corresponds to the ordering S1, S2, ..., Sn of the domains on which R is defined (see, however, remarks below on domain-ordered and domain-unordered relations).

5. The significance of each column is partially conveyed by labeling it with the name of the corresponding domain."

-- A relational model of data for large shared data banks[1]

[1]: https://cs.uwaterloo.ca/~david/cs848s14/codd-relational.pdf

Re:Migrating to Python 3 with pleasure by djrobstep on Monday February 05, 2018 @05:59PM (#16313034)
> Shouldn’t the collection of rows be a set or list, not a dictionary?

I didn't mention the collection of rows, I mentioned the rows themselves.

> The “rows themself” being an ordered map means you are referring to the columns

No, it means I'm referring to the rows themselves.

The rows themselves are each ordered mappings.

Hope this helps to clarify things. Happy to keep repeating this as many times as necessary.

Re:Migrating to Python 3 with pleasure by dragonwriter on Monday February 05, 2018 @06:08PM (#16313096)
I think the confusion is your use of “columns” or “columns of the row” to refer to attribute-value pairs that make up the row.
Re:Migrating to Python 3 with pleasure by icedchai on Sunday February 04, 2018 @10:07PM (#16306331)
Unless there is an "order by" clause, the order of rows in the result set is undefined and non-deterministic from query to query.
Re:Migrating to Python 3 with pleasure by djrobstep on Sunday February 04, 2018 @11:35PM (#16306616)
As I said:

> Not the result set, the rows of the result set.

Each row is a mapping with ordered keys.

Re:Migrating to Python 3 with pleasure by icedchai on Monday February 05, 2018 @09:17AM (#16308831)
Perhaps you are confused and mean "columns"? ("Rows of the result set" is what I was referring to.)

A result set has rows, which are not in a deterministic order unless an "order by" is provided. Each row has columns. The columns are in order, obviously.

Re:Migrating to Python 3 with pleasure by djrobstep on Monday February 05, 2018 @05:26PM (#16312818)
Perhaps you are confused and think I'm talking about the ordering of the result set.

I said that database query result rows are made up of ordered dictionaries. I didn't mention ordering of the result set.

Happy to keep repeating this as many times as necessary.

Re:Migrating to Python 3 with pleasure by icedchai on Tuesday February 06, 2018 @11:46AM (#16317438)
ok. We're actually saying the same thing, just in different words.
Re:Migrating to Python 3 with pleasure by larrykwg on Sunday February 04, 2018 @09:43PM (#16306261)
I have the opposite reaction to it, it seems insanely idiotic to have a associative array with ordered keys. It can only make sense to someone who doesn't know anything about fundamental data structures and a language that caters to people like that in spite of the performance penalty is just strange.

but hey, its Guido, I still can't fathom that he moved reduce into functools.

Re:Migrating to Python 3 with pleasure by goerz on Sunday February 04, 2018 @09:56PM (#16306306)
I vaguely remember that the change to ordered keys in 3.6 was actually a side effect of making the dict implementation more efficient!

https://mail.python.org/pipermail/python-dev/2016-September/...

Re:Migrating to Python 3 with pleasure by sametmax on Monday February 05, 2018 @01:28AM (#16307012)
Well, given that I used reduce twice in production in 14 years of Python, my guess is that you are using Python wrong.
Re:Migrating to Python 3 with pleasure by djrobstep on Monday February 05, 2018 @12:43AM (#16306860)
Putting aside the fact that this change was made to increase performance, I'd rather have a language that's useful, expressive, and semantically powerful by default, instead of one that is less powerful and harder to use but slightly faster.
Re:Migrating to Python 3 with pleasure by improv32 on Sunday February 04, 2018 @07:44PM (#16305832)
The data structure OrderedDict does what you describe and has been in the stdlib since I think 2.7
Re:Migrating to Python 3 with pleasure by djrobstep on Sunday February 04, 2018 @08:39PM (#16306041)
Indeed, but it's much nicer when it's universal and built-in rather than requiring a specific import and different, more cumbersome syntax.
Re:Migrating to Python 3 with pleasure by dbcurtis on Sunday February 04, 2018 @11:42PM (#16306643)
Ordereddict has been available for ages. Why should I pay for the overhead in the 98% of the cases where I don't need it.
Re:Migrating to Python 3 with pleasure by alexbecker on Monday February 05, 2018 @12:10AM (#16306745)
The new dict implementation was introduced in 3.5 (with forced order randomization, which was removed in 3.6) because it is faster and uses less memory than the previous non-ordered dict. Ordering is merely a nice byproduct. So you're not paying any penalty.

OrderedDict is fundamentally different because it is designed to allow inserting/removing keys in the middle of the ordering in O(1) time. It does not use the new dict under the hood, or vice-versa.

Re:Migrating to Python 3 with pleasure by sametmax on Monday February 05, 2018 @01:27AM (#16307008)
Actually, 3.7 are not always ordered. If you delete a key, order is not guaranteed anymore. For performance reasons.
Re:Migrating to Python 3 with pleasure by Sean1708 on Monday February 05, 2018 @09:16AM (#16308824)
Are you sure about that? I thought they considered that but decided to just make them always ordered in the end.
Re:Migrating to Python 3 with pleasure by jsmeaton on Monday February 05, 2018 @12:05AM (#16306721)
Keeping the dict ordered is actually faster. There’s a link to a YouTube talk a little upthread that discusses the algorithms used. It’s really interesting.
Re:Migrating to Python 3 with pleasure by doug1001 on Monday February 05, 2018 @01:13AM (#16306964)
agree completely

aside from that, python has a separate ordered dict class

Re:Migrating to Python 3 with pleasure by sametmax on Monday February 05, 2018 @01:38AM (#16307056)
Before 3.7, dict ordering is documented literally everywhere as "consider it implementation details, use OrderedDict if you need order". From 3.7, it's part of the spec.

If you were relying on keys order before, you were not only doing it wrong, but you were doing so despite being told again and again.

Re:Migrating to Python 3 with pleasure by StreakyCobra on Monday February 05, 2018 @05:17AM (#16307841)
This has been changed in Python 3.6 only, due to a change in dictionary implementation to make them more efficient. "Modern Dictionaries by Raymond Hettinger" [1] is a quite interesting and technical talk about these changes, explaining also the change in iteration order IIRC, worth a watch in my opinion!

[1] https://www.youtube.com/watch?v=p33CVV29OG8

Re:Migrating to Python 3 with pleasure by cup-of-tea on Monday February 05, 2018 @04:02AM (#16307567)
This is why you read the documentation rather than relying on what a piece of library code appears to do. Maybe all programmers have to learn this the hard way.