Path: csiph.com!fu-berlin.de!uni-berlin.de!not-for-mail From: Marco Sulla Newsgroups: comp.lang.python Subject: Re: Suggestion: make sequence and map interfaces more similar Date: Sat, 26 Mar 2016 01:18:47 +0100 Lines: 211 Sender: elbarbun@gmail.com Message-ID: References: <56f27d76$0$1600$c3e8da3$5496439d@news.astraweb.com> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 X-Trace: news.uni-berlin.de ngt/mUzTF7jL/r8a7zDorQybHRb6ZaN1lTpdseUlUThA== Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.000 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'received:209.85.223': 0.03; 'value,': 0.03; 'that?': 0.05; '*not*': 0.07; 'append': 0.07; 'difference,': 0.07; 'method,': 0.07; 'only,': 0.07; 'reason,': 0.07; 'run,': 0.07; 'type,': 0.07; 'cc:addr:python- list': 0.09; '(string,': 0.09; '*value*': 0.09; 'behave': 0.09; 'dict': 0.09; 'eat': 0.09; 'forcing': 0.09; 'int)': 0.09; 'iterate': 0.09; 'obj': 0.09; 'tuple': 0.09; 'untouched.': 0.09; 'url:github': 0.09; 'wrong,': 0.09; 'example:': 0.10; 'def': 0.13; 'suggest': 0.15; 'wed,': 0.15; 'value.': 0.15; '"d"': 0.16; '"key"': 0.16; "'a',": 0.16; "'b',": 0.16; "'z')": 0.16; '(key,': 0.16; '*no*': 0.16; '2016': 0.16; "['a',": 0.16; 'appends': 0.16; 'birds': 0.16; 'door.': 0.16; 'hypothetical': 0.16; 'iterable': 0.16; 'iterates': 0.16; 'keys.': 0.16; 'logical,': 0.16; 'mapping,': 0.16; 'mappings.': 0.16; 'parameter,': 0.16; 'received:io': 0.16; 'received:psf.io': 0.16; 'sequence.': 0.16; 'subject:interfaces': 0.16; 'subject:make': 0.16; "to:name:steven d'aprano": 0.16; 'url:py': 0.16; 'useless': 0.16; 'wrote:': 0.16; "wouldn't": 0.16; 'string': 0.17; 'sender:addr:gmail.com': 0.18; "shouldn't": 0.18; '>': 0.18; 'accepting': 0.18; 'input': 0.18; 'cc:2**0': 0.20; 'cc:addr:python.org': 0.20; 'extension': 0.20; "aren't": 0.22; 'keys': 0.22; 'parameter': 0.22; 'simpler': 0.22; 'pass': 0.22; 'programming': 0.22; 'am,': 0.23; 'code,': 0.23; 'bit': 0.23; 'seems': 0.23; 'ease': 0.23; 'header:In-Reply-To:1': 0.24; 'sort': 0.25; "i've": 0.25; "doesn't": 0.26; 'sense': 0.26; 'equivalent': 0.27; 'message-id:@mail.gmail.com': 0.27; 'back.': 0.27; 'moved': 0.27; 'sequence': 0.27; 'start,': 0.27; 'function': 0.28; 'this.': 0.28; 'values': 0.28; 'skip:( 20': 0.28; 'interface': 0.29; 'about.': 0.29; 'accepts': 0.29; 'behaviour': 0.29; 'exists,': 0.29; 'key,': 0.29; 'occasionally': 0.29; 'perl': 0.29; 'sensible': 0.29; 'str': 0.29; 'sure,': 0.29; 'types.': 0.29; 'value)': 0.29; 'too.': 0.30; 'url:mailman': 0.30; 'code': 0.30; 'certainly': 0.30; 'putting': 0.30; 'somebody': 0.30; 'extend': 0.31; 'probably': 0.31; "can't": 0.32; 'noticed': 0.32; 'maybe': 0.33; 'getting': 0.33; 'point': 0.33; 'useful': 0.33; 'class': 0.33; 'url:python': 0.33; 'usually': 0.33; "d'aprano": 0.33; 'steven': 0.33; 'values.': 0.33; 'url:listinfo': 0.34; 'case,': 0.34; 'this?': 0.34; 'handle': 0.34; 'day': 0.67; 'float:': 0.72; 'treat': 0.72; 'useful.': 0.72; 'introduce': 0.79; 'dict,': 0.84; 'dict.': 0.84; 'float,': 0.84; 'goose': 0.84; 'lays': 0.84; 'url:master': 0.84; 'different.': 0.91; 'dog.': 0.91; 'legs': 0.91; 'succeed.': 0.91; 'gaps': 0.93; 'thing,': 0.93; 'imagine': 0.96 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:sender:in-reply-to:references:from:date:message-id :subject:to:cc; bh=A2BK6FrRPiyS8unAymAdNbZOrCkfAD1GzfJnfUXUni8=; b=meNYwwK/oa5oF5PJKvhU0DHnXquESRQnAyqUH8odoru9PbzrHWW3FmcLuG5KjsYiIY YrcR44UBTn53oHr9HV80NqvPho9x5F0KIKY53pDUIPtSdFT1/nuUijXN1dQNUu4snnNh Q3iDHqF5d9QMwiRG9uPVbc8D8wNYX+YhJ67d347NEn5GylKb96RrJjpFXUHht70c+Y3A AWyBswSu2NYVOD0zMuQ9ZMzRQwDnyfGlPA+Cu0UsDAwYW8/bALYlaSzkQ7++h4UDd+Nc CSQbsZflSqE/9nGusyEv1ZDBI1Vjv6jOFVf0owykk3bCO3gApkeh3aCFpsRd5pxo0XWN u2UA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:sender:in-reply-to:references:from :date:message-id:subject:to:cc; bh=A2BK6FrRPiyS8unAymAdNbZOrCkfAD1GzfJnfUXUni8=; b=V7DPGPn28Sp03Twh7EKS6scDewKYqKvAPdSnmyCqC6Hrb0lbp++8lBv794YjeD5grh yAs83yYrEGq+0NkoSb1JmnyLXgtupfZz1vkDBAkRbXIKwS0q2ys35l3gNN8XtvwJGH9s 9TFh4T/Oq5ubPclbr57IAtLv+2UqRNv/3ceqaLMWgIceRqWOIpZzgqjpYzfe9ImByPhy Z0LP+TXeskx1J98z1PodjIOdYIX49XY+wiuYhEbVvXOG21noMMufcbBO98UuWb0pd6gd GQG97pC8UWtkl4FOL4zNM5HYaumlxxXtLPh52eD+s6w6nNNViQmtxCl0PZUPRGHZ6aK8 AZVg== X-Gm-Message-State: AD7BkJKwgJ+XvkgH5nqAmeD64+VpAinjcS6BkaDYBFH+5P4Xz3rUQup20ct+ir/NOAOkcI+VMWd8AaQfQZWobg== X-Received: by 10.107.168.81 with SMTP id r78mr15683154ioe.179.1458951566860; Fri, 25 Mar 2016 17:19:26 -0700 (PDT) In-Reply-To: <56f27d76$0$1600$c3e8da3$5496439d@news.astraweb.com> X-Google-Sender-Auth: WZgGizwaYtyIPNDAJVEzX-TEowM X-Mailman-Approved-At: Sat, 26 Mar 2016 05:59:33 -0400 X-Content-Filtered-By: Mailman/MimeDel 2.1.21 X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Xref: csiph.com comp.lang.python:105734 > That's a very superficial similarity: a list ['a', 'b', 'x', 'y'] is > something like a mapping {0: 'a', 1: 'b', 2: 'x', 3: 'y'}. Seems logical, > since in both cases we write collection[2] and get 'x' back. > > But think about it a bit more, and you will see that the behaviour is in > fact *very different*. For example: > > the_list = ['a', 'b', 'x', 'y'] > # the_list is equivalent to {0: 'a', 1: 'b', 2: 'x', 3: 'y'} > the_list.insert(0, 'z') > # the_list is now equivalent to {0: 'z', 1: 'a', 2: 'b', 3: 'x', 4: 'y'} > > Every existing "key:value" pair has changed! What sort of mapping operates > like that? It's like you said: "Animals with four legs can usually run, eat etc. But birds can fly! What sort of animal flies?" Well. birds. You can easily extend dict and create a new class that imitate list, tuple or str without any problem. Sequences are an extension of maps. > Have you ever actually wanted to use sequences or maps indifferently? To do > what? Not my code, but this is an example: https://github.com/thieman/dagobah/blob/master/dagobah/daemon/daemon.py def replace_nones(dict_or_list), line 27 On 23 March 2016 at 12:26, Steven D'Aprano wrote: > On Wed, 23 Mar 2016 06:54 am, Marco S. wrote: > > > I noticed that the sequence types does not have these methods that the > map > > types has: get(), items(), keys(), values(). > > > > It could seem useless to have them for sequences, > > That's putting it mildly. > > > but I think it will ease > > the creation of functions and methods that allow you to input a generic > > iterable as parameter, but needs to use one of these methods in case the > > parameter is a map. > > Perhaps it would. But countering that is the disadvantage that you're > adding > methods to sequences that have no sensible meaning for a sequence. > > Strings and floats are quite different things, but occasionally it makes > sense to write a function that accepts either a string or a float. Perhaps > we could introduce methods to strings and floats to blur the difference, > to "ease the creation of functions and methods that allow you to input a > generic scalar (string, float, int) as parameter..."? > > Some of these methods would be easy: > > class float: > def upper(self): > return self > > > Some a bit more work: > > def find(self, substring, start, end): > s = str(self) > return s.find(substring, start, end) > > but some perplex me. What would (27.25).expand_tabs() do? > > > Of course this is silly. Even Perl and Javascript don't go this far in > making floats and strings interchangeable. This is a good thing: if you're > calling some_float.upper(), you've almost certainly made a programming > error, and you don't want this nonsensical method call to silently succeed. > > So it is with sequences and mappings. They are *not* the same sort of > thing, > even though they have a few superficial similarities, and they shouldn't > try to behave as the same thing. > > What should some_dict.append(None) do? The very concept is nonsense: dicts > aren't *ordered sequences*, you can't append to a dict. Maybe you could > give dicts a method *called* "append", but it wouldn't mean the same thing > as list.append, and it probably wouldn't have the same signature: > > > list.append(value) > Appends value to the end of the list. > > dict.append(key, value) > Adds a new key to the dict, with the given value. > Same as dict[key] = value. > > > Forcing these two completely different methods to have the same name > doesn't > do anything useful. That's like putting a door handle on your iPhone, in > case some day you want to treat your iPhone as a door. > > > > In one word, it will facilitate duck typing. > > I think you have misunderstood the purpose and meaning of duck-typing. > > Duck-typing is not about forcing unrelated, dissimilar types to have the > same interface just in case you want to write a function that will accept > either type. > > Duck-typing is about accepting anything which "quacks like a duck". If all > you need is something which lays an egg, you shouldn't care whether it is a > chicken or a goose or a duck. It doesn't mean that dogs and cats should > have a "lay_egg" method, just in case somebody wants to accept a duck or a > dog. > > > > For the same reason, I would suggest the introduction of a new map type, > > vdict, a dict that by default iterates over values instead over keys. So > a > > vdict object "d" wiil have iter(d) == iter(d.values()), and should also > > have a count() method, like sequence types. > > I don't really see the point in this. What sort of function will expect to > iterate over a mapping, but not care whether it is getting keys or values? > > Sure, there are generic functions that will iterate over *any iterable*, > and > you can pass dict.keys() or dict.values(), and both will work fine. That's > exactly what duck-typing is about. > > But let's imagine this hypothetical function that will accept any mapping, > and some mappings will iterate over keys and some mappings iterate over > values. What would you do with it? > > def walk(the_dict): > for obj in the_dict: > print("Key =", obj) # That's wrong, it might be a value. > value = the_dict[obj] # That's wrong too. > the_dict[obj] = "processed" # Still wrong. > > > There's nothing useful or interesting you can do with a mapping and > something which might be a key, or might be a value, but you don't know > which. You can treat them in isolation, as if they had nothing to do with a > dict, and that's about it. But in that case, why insist on a dict? > > walk(the_dict.keys()) > walk(the_dict.values()) > walk(the_list) > walk(the_iterator) > > > > Indeed sequences are, in my humble opinion, a specialized case of maps, > > when keys are numeric only, are always contiguous without gaps and start > > from 0. > > That's a very superficial similarity: a list ['a', 'b', 'x', 'y'] is > something like a mapping {0: 'a', 1: 'b', 2: 'x', 3: 'y'}. Seems logical, > since in both cases we write collection[2] and get 'x' back. > > But think about it a bit more, and you will see that the behaviour is in > fact *very different*. For example: > > the_list = ['a', 'b', 'x', 'y'] > # the_list is equivalent to {0: 'a', 1: 'b', 2: 'x', 3: 'y'} > the_list.insert(0, 'z') > # the_list is now equivalent to {0: 'z', 1: 'a', 2: 'b', 3: 'x', 4: 'y'} > > Every existing "key:value" pair has changed! What sort of mapping operates > like that? > > del the_list[2] > # the_list is now equivalent to {0: 'z', 1: 'a', 2: 'x', 3: 'y'} > > I've said to delete the "key" 2, but there it still is. "Key" 2 still > exists, it just has a different value! And it is "key" 4 which has been > deleted! But not the *value* attached to "key" 4, that's been moved to 3! > > What sort of crazy mapping behaves like this? > > The answer is, of course, *no* sort of mapping. Sequences are not mappings. > The only reason we think of them as kinda-sorta like mappings is because of > a superficial similarity between key:value and index:item. That similarity > is real, but virtually everything else about mappings and sequences is > different. > > > > > This way we will have a simpler way to let people to use sequences > > or maps indifferently, and let the code untouched. > > Have you ever actually wanted to use sequences or maps indifferently? To do > what? > > The only case I've ever seen of that is the dict constructor, and > dict.update, which will accept either a mapping or a sequence of (key, > value) pairs. > > > > > -- > Steven > > -- > https://mail.python.org/mailman/listinfo/python-list >