Inconsistent Auto-Vivification
>>> a=7
>>> b['five']=5
Traceback (most recent call last):
File "", line 1, in
NameError: name 'b' is not defined
This may be a tad unfair, as 'b[...]' could represent an array, but it's clear that 'b[string]' is not an array. Let's try arrays:
>>> b=list()
>>> b[5]=7
Traceback (most recent call last):
File "", line 1, in
IndexError: list assignment index out of range
Oh I've gone too far?...
>>> b[0]=1
Traceback (most recent call last):
File "", line 1, in
IndexError: list assignment index out of range
So it's not possible to put anything into an array?
Why is auto-vivification useful? Let's try to record how many times each character is found:
>>> seen=dict()
>>> for l in 'here is a string':
... seen[l]+=1
...
Traceback (most recent call last):
File "", line 2, in
KeyError: 'h'
Oh darn. This isn't going to be simple after all...
>>> import json
>>> seen=dict()
>>> for l in 'here is a string':
... try:
... seen[l]+=1
... except KeyError:
... seen[l]=1
...
>>> print json.dumps(seen)
{'a': 1, ' ': 3, 'e': 2, 'g': 1, 'i': 2, 'h': 1, 'n': 1, 's': 2, 'r': 2, 't': 1}
This means that list comprehensions, which are their own form of loathesome, are pretty much useless.
Compare with Perl (where a string is a string, not a list, so we'll have to split):
use JSON;
my %seen=();
foreach $l (split(//,'here is a string')) { $seen{$l}++ }
print encode_json(\%seen),"\n";
{"e":2,"n":1,"a":1," ":3,"r":2,"s":2,"h":1,"g":1,"i":2,"t":1}
(Well, you wanted JSON instead of Dumper output, presumably.) Here's the equivalent of a list comprehension; in Perl, it works:
map {$seen{$_}++} split(//,'here is a string');
Let's try another one. One hundred, indexed entries of names are arriving in an unknown order. We want them to be stored/processed/returned in index order (or the index wouldn't even be there wasting space in the first place). We'll start with Perl:
my @entries=();
while(<>) { chomp;
my ($idx,$name)=split(/\t/,$_,2);
$entries[$idx]=$name;
}
With the discovery of the list.insert method (!), here's a Python program to do the same thing:
import fileinput
entries=list()
for line in fileinput.input():
(idx,name)=line.rstrip("\n").split("\t",1)
entries.insert(int(idx),name)
This works well until:
>>> a=list()
>>> a.append(0)
>>> a.insert(9,9)
>>> print a
[0, 9]
>>> print a[1]
9
>>> print a[9]
Traceback (most recent call last):
File "", line 1, in
IndexError: list index out of range
So it's pure luck that this works?
>>> a.insert(2,2)
>>> a.insert(0,0)
>>> a.insert(1,1)
>>> print a
[0, 1, 2]
And if the list is being used during construction, all bets are off:
>>> def check(a,b):
... cnt=0
... for i in range(0,len(a)):
... if i%2==0:
... cnt+=1
... b.append(cnt)
...
>>> a=list()
>>> b=list()
>>> a.insert(2,2)
>>> check(a,b)
>>> print b
[1]
>>> a.insert(0,0)
>>> check(a,b)
>>> print b
[1, 1]
>>> a.insert(1,1)
>>> check(a,b)
>>> print b
[1, 1, 2]