tag:blogger.com,1999:blog-496482.post8629313830167737814..comments2024-03-26T03:20:19.840-04:00Comments on For Some Value of "Magic": Why Tuples?Stevehttp://www.blogger.com/profile/15732819755000554717noreply@blogger.comBlogger26125tag:blogger.com,1999:blog-496482.post-17616603423359928062013-05-04T06:54:54.950-04:002013-05-04T06:54:54.950-04:00@Andrew: Well, I believe we are largely in agreeme...@Andrew: Well, I believe we are largely in agreement, but there is the valid point that unpacking assignments to the elements is a (somewhat) desirable feature. Does unpacking assignment rely on __getitem__(), or does it use __next__() and the iteration protocol?Stevehttps://www.blogger.com/profile/15732819755000554717noreply@blogger.comtag:blogger.com,1999:blog-496482.post-88326793444425170052013-05-04T06:43:24.730-04:002013-05-04T06:43:24.730-04:00I believe I'd rather know how it behaved than ...I believe I'd rather know how it behaved than have to think of it like that. From the outside Haskell seems disciplined and difficult, but people I respect in the Python world speak highly of it. I tend to think of it as the bastard child of ML and LISP. Ignorance is Bliss.Stevehttps://www.blogger.com/profile/15732819755000554717noreply@blogger.comtag:blogger.com,1999:blog-496482.post-90742594118398952572013-05-04T06:30:51.900-04:002013-05-04T06:30:51.900-04:00And of course in Haskell they're called produc...And of course in Haskell they're called product types. So given a tuple of (A, B) you can think of it as a cross product of anything from the A's and the set of B's.bootheadhttps://www.blogger.com/profile/12741524681973967716noreply@blogger.comtag:blogger.com,1999:blog-496482.post-71527522059834601342013-04-29T05:51:47.722-04:002013-04-29T05:51:47.722-04:00The classic use-case which tests any guideline abo...The classic use-case which tests any guideline about tuples is the class __bases__ attribute. It returns a tuple. Generally speaking, it needs to be an immutable ordered collection of class-like object, where the length can be different for different classes. Python's tuple() is a perfect fit for this, and no other container comes close.<br /><br />This case breaks most tuple guidelines: There is no meaning to a position beyond its relative ordering. Iterating over the base classes does make sense for some cases, such as building an inheritance diagram. It's not used as a dictionary key. Its members are homogenous.<br /><br />FWIW, my biggest gripe about using namedtuples as light-weight immutable classes is the lingering ability to use indexing. Namedtuples are great as a backwards-compatible transition from tuples to class-like objects, which was needed for os.stat() and time.gmtime(). But in my own code I want the ability to transition from a nametuple to a class, without worrying that users of my API might have been using the getitem interface that I didn't want to implement. While people might also use the _asdict and _replace methods, it's a big temptation in inner loops to use obj[1] instead of obj.green (as with an RGB color class) because index lookup in a namedtuple is twice as fast as property lookup.<br />Andrew Dalkehttps://www.blogger.com/profile/17091314849699854287noreply@blogger.comtag:blogger.com,1999:blog-496482.post-20523595606555131642013-04-29T04:15:33.556-04:002013-04-29T04:15:33.556-04:00@anonymous: that sounds reasonable. Thanks for the...@anonymous: that sounds reasonable. Thanks for the example.Stevehttps://www.blogger.com/profile/15732819755000554717noreply@blogger.comtag:blogger.com,1999:blog-496482.post-36207195396569756772013-04-29T04:02:41.552-04:002013-04-29T04:02:41.552-04:00@Samus: Leaving aside the unnecessary parentheses,...@Samus: Leaving aside the unnecessary parentheses, consider for example a memoizing function that remembers its arguments (a, b, c) and caches the result to avoid duplicating expensive computations. The natural way to store previously-seen arguments is as a dict, keyed by the tuple of argument values.<br /><br />The basis logic (and sorry for Blogger's horrendous code mangling, by the way) would look like:<br /><br /><br />stash = {}<br />def f(a, b, c):<br />if (a, b, c) in stash:<br />return stash[a, b, c]<br />else:<br /># long expensive computation<br />stash[a, b, c] = result<br />return result<br /><br /><br />In case this too gets mangled the source is stored as as <a href="http://pastebin.com/zmZQh8n1" rel="nofollow">Memoizing function skeleton</a> on Pastebin with permanent retention. [Note: there's even a mistake on Pastebin, where the final return statement is indented one level too many]. If you can think of a more natural way to do this I will be interested to hear it.<br /><br />Once again, I make the point that this was not the issue I started out to discuss. So while it's interesting it should be regarded as a "rathole" tending towards derailing discussion of the point I was originally trying to make. Sure, you are interested in it, but why do you imagine I should be? Would silence have been an acceptable response?<br /><br />I was really just asking whether it might be a good idea to have a standard library equivalent of the fairly well-known "bunch" pattern. I believe (though would be happy to be corrected) that namedtuple is currently the nearest we have.<br /><br />For extra points the interested reader should demonstrate a memoizing function that also accepts keyword arguments.Stevehttps://www.blogger.com/profile/15732819755000554717noreply@blogger.comtag:blogger.com,1999:blog-496482.post-22746170164624843222013-04-29T03:57:54.309-04:002013-04-29T03:57:54.309-04:00This comment has been removed by the author.Stevehttps://www.blogger.com/profile/15732819755000554717noreply@blogger.comtag:blogger.com,1999:blog-496482.post-70637500508030753902013-04-29T03:18:30.186-04:002013-04-29T03:18:30.186-04:00I unpack from struct.unpack into a namedtuple. A t...I unpack from struct.unpack into a namedtuple. A tuple subclass with property accessors is perfect for my needs. Don't mess with namedtuple...<br /><br />There's the built-in namespace object in version 3.3, i.e. types.SimpleNamespace. In 3.3 it's used by sys.implementation and time.get_clock_info(). Basically, it's like a heap type defined with __slots__ = ('__dict__',), so no weak references.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-496482.post-60796091911938362552013-04-29T03:02:35.055-04:002013-04-29T03:02:35.055-04:00mydict[('some', 'random', 'stu...mydict[('some', 'random', 'stuff')] = 'really?'<br /><br />no seriously, I haven't seen this anywhere and it's a terrible idea imho.Samus_https://www.blogger.com/profile/05348475764487637379noreply@blogger.comtag:blogger.com,1999:blog-496482.post-71191533739297234942013-04-29T02:17:05.363-04:002013-04-29T02:17:05.363-04:00Yes, one could, But to do so would be a perversion...Yes, one could, But to do so would be a perversion building, as it does, one unsatisfactory layer on top of another.<br /><br />Fortunately Raymond knows where to stop, and so we have namedtuple instead. I was wondering whether a slimmed-down version (something like the bunch class) might be useful, not considering adding more cruft!<br /><br />This does neatly demonstrate the Python geek tendency to focus on ever more peripheral questions. Let's try and resist that, shall we?Stevehttps://www.blogger.com/profile/15732819755000554717noreply@blogger.comtag:blogger.com,1999:blog-496482.post-34389308461265109482013-04-29T01:56:36.742-04:002013-04-29T01:56:36.742-04:00# It is possible to subclass a namedtuple:
from c...# It is possible to subclass a namedtuple:<br /><br />from collections import namedtuple<br />fields = ('states', 'symbols', 'transition', 'initial', 'accepting_states')<br />NFA = namedtuple('NFA', fields)<br />_nfa = NFA(*fields)<br />_nfa._fields, _nfa._asdict()<br /><br />class NFAWithMethods(NFA):<br /> def print_symbols(self):<br /> print(self.symbols)<br /><br />_nfa = NFAWithMethods(*fields)<br />_nfa.print_symbols()<br />Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-496482.post-55253092944751538302013-04-28T20:09:07.583-04:002013-04-28T20:09:07.583-04:00@Johann: Yes, I agree, the immutability and speed ...@Johann: Yes, I agree, the immutability and speed are important reasons for choosing a named tuple. The dict is far too general a data structure to be efficient in applications like those you mention.Stevehttps://www.blogger.com/profile/15732819755000554717noreply@blogger.comtag:blogger.com,1999:blog-496482.post-71574536447524687492013-04-28T20:01:15.399-04:002013-04-28T20:01:15.399-04:00@toddrme2178, @Steve:
One main reason for using na...@toddrme2178, @Steve:<br />One main reason for using namedtuples over dicts is for performance and to reduce memory usage, as well as being immutable.<br /><br />dynamic dicts can really hurt performance if you're instantiating a lot at a time, and it's wasteful if you can do the same exact thing with a namedtuple, especially when immutability makes sense for the object.<br /><br />Consider a namedtuple that represents a specific sequence of bytes for a file. You might want to have <b>filepath</b>, <b>memory_address</b>, <b>sequence</b>. You aren't editing the files, so you just want to scrape through a filesystem and figure out which files have that sequence, therefore you don't want to change the values ever. If you might find 20 millions instances of that sequence, you can save a lot of RAM by using a named tuple, and it represents an object which can and should be immutable.<br /><br />I've seen this sort of thing in practice, namedtuples make the most sense, and it can really improve performance if you're doing this at a large scale.Johan Nestaashttps://www.blogger.com/profile/02667300764349358434noreply@blogger.comtag:blogger.com,1999:blog-496482.post-39839820922375519852013-04-28T18:00:54.430-04:002013-04-28T18:00:54.430-04:00I wish Python had an equivalent to Javascript'...I wish Python had an equivalent to Javascript's <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/freeze" rel="nofollow">Object.freeze</a> so that tuples wouldn't see so much abuse as frozen lists.<br /><br />PEP-351, "The freeze protocol" was rejected, but that dealt with creating a hashable copy rather than simply disabling further mutation of an existing object.Laurence Rowehttps://www.blogger.com/profile/02164563755538372331noreply@blogger.comtag:blogger.com,1999:blog-496482.post-61834739442261336092013-04-28T12:33:12.656-04:002013-04-28T12:33:12.656-04:00We use TCP/IP five tuples as keys in a dictionary ...We use TCP/IP five tuples as keys in a dictionary of connection specific data.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-496482.post-47007422020796744582013-04-28T11:27:56.578-04:002013-04-28T11:27:56.578-04:00@toddr2178: Your point being?
@claudio: Good poin...@toddr2178: Your point being?<br /><br />@claudio: Good point.<br /><br />@Samus_: You made that up, didn't you? Tuples are used as dict keys all the time.Stevehttps://www.blogger.com/profile/15732819755000554717noreply@blogger.comtag:blogger.com,1999:blog-496482.post-16343171829439486912013-04-28T10:37:30.908-04:002013-04-28T10:37:30.908-04:00tuples are cheaper in terms of memory, that's ...tuples are cheaper in terms of memory, that's the only reason they exist.<br /><br />everything that can be done with a tuple can (and usually is) done with a list.<br /><br />in Haskell a 2-tuple is different than a 3-tuple and (str, int) is different from (int, str) but Python won't bother, the wrong tuple will fail the same as the wrong list.<br /><br />the only thing tuples can do that lists not is being hashed but I doubt a tuple was used as a key to anything ever.Samus_https://www.blogger.com/profile/05348475764487637379noreply@blogger.comtag:blogger.com,1999:blog-496482.post-50758913201726752972013-04-28T10:32:09.623-04:002013-04-28T10:32:09.623-04:00tuples are cheaper in terms of memory, that's ...tuples are cheaper in terms of memory, that's the only reason they exist.<br /><br />anything that can be done with a tuple can (and most of the time is) done with a list.<br /><br />in Haskell a 2-tuple is different from a 3-tuple so it make more sense in the context exposed on this article but Python won't bother, it'll fail with the wrong sized tuple the same way it would with a wrong sized list.Samus_https://www.blogger.com/profile/05348475764487637379noreply@blogger.comtag:blogger.com,1999:blog-496482.post-50685132237749628392013-04-28T10:31:27.140-04:002013-04-28T10:31:27.140-04:00"...perhaps it's time to either remove na..."...perhaps it's time to either remove namedtuple's __getitem__() and similar methods or implement a similar object without the sequence behaviors"<br /><br />What if I want to use some generic code to "trying to save its state during a pickling operation or some more obscure book-keeping metacode"claudio canepahttps://www.blogger.com/profile/07607460284839405974noreply@blogger.comtag:blogger.com,1999:blog-496482.post-2658117427538146962013-04-28T09:06:15.931-04:002013-04-28T09:06:15.931-04:00You can for ordereddict.You can for ordereddict.toddrme2178https://www.blogger.com/profile/03684472911091668339noreply@blogger.comtag:blogger.com,1999:blog-496482.post-60534984014642702992013-04-28T06:18:08.416-04:002013-04-28T06:18:08.416-04:00Perhaps you can, but you cannot predict the order ...Perhaps you can, but you cannot predict the order in which the values will be produced, so it isn't very useful for an unpacking assignment, is it?Stevehttps://www.blogger.com/profile/15732819755000554717noreply@blogger.comtag:blogger.com,1999:blog-496482.post-30739184671451332172013-04-28T06:14:07.014-04:002013-04-28T06:14:07.014-04:00Yes, the syntax is a little shorter. On the other...Yes, the syntax is a little shorter. On the other hand it muddles the distinction between keys and class attributes.<br /><br />And you can do unpacking assignment with an orderdict using .values().toddrme2178https://www.blogger.com/profile/03684472911091668339noreply@blogger.comtag:blogger.com,1999:blog-496482.post-15638081241944820512013-04-28T05:50:23.054-04:002013-04-28T05:50:23.054-04:00To access element joe from a dict you must write
...To access element joe from a dict you must write<br /><br /><br /> x = d["joe"]<br /><br />whereas to access the same element in a named tuple you would write'<br /><br /> v = d.joe<br /><br />When the names are known this is a much simpler way to write the equivalent acces. And, as Nick pointed out, you can't use unpacking assignments with a dict.Stevehttps://www.blogger.com/profile/15732819755000554717noreply@blogger.comtag:blogger.com,1999:blog-496482.post-1620803006166250212013-04-28T05:08:10.766-04:002013-04-28T05:08:10.766-04:00I get that much.
But now that the conversation ...I get that much. <br /><br />But now that the conversation has veered off into named tuples, what I don't really understand is the advantage of named tuples over dicts (or at least orderedicts).toddrme2178https://www.blogger.com/profile/03684472911091668339noreply@blogger.comtag:blogger.com,1999:blog-496482.post-63392843939667359082013-04-28T03:52:03.804-04:002013-04-28T03:52:03.804-04:00Sure, I wasn't suggesting that classic tuples ...Sure, I wasn't suggesting that classic tuples should be discarded - simply that I doubt named tuples are indexed very much.Stevehttps://www.blogger.com/profile/15732819755000554717noreply@blogger.com