After a great many months, I have likely forgotten most of the examples of how utterly stupid Python behavior generally is, so I'll try to start collecting what manner of insanity I can either recall or otherwise newly discover.

yield destroys logic

Tis awful for shell scripting

Tis awful for shell scripting too

Range is inclusive/exclusive

Hash implementation isn't very intelligent

Dictionary syntax is inconsistent

Loop implementation isn't very smart

Lists... aren't

None is a tragedy

Printing is complicated

Regular expressions combine poorly

Regular expression substitutions are cumbersome

Set Syntax Silliness

Inconsistent Auto-Vivification

yield destroys logic

The following does not raise an error:

#!/usr/bin/python

def test(vara):
  if vara is None:
    raise NotImplementedError
  ids=["one", "two", "three"]
  for id in ids:
    yield id.strip()

result=test(None)

The following does raise an error:

#!/usr/bin/python

def test(vara):
  if vara is None:
    raise NotImplementedError
  ids=["one", "two", "three"]
  for id in ids:
    yield id.strip()

result=test(None)
for id in result:
  print "ID=%s" % id

Tis awful for shell scripting

Consider a common task in a shell script: Run a command, pipe it through grep, and fetch the first result; store that result to a variable. For this example, we'll use a silly command like `ls`. Let's suppose we're not interested in stderr.

Bash:

VAR=`ls | grep a | head -n1`
echo $VAR

Perl:

my $var=qx/ls | grep a | head -n1/; chomp($var);
print $var,"\n"

Python:

VAR=subprocess.Popen("ls | grep a | head -n1",
  shell=True, stdout=subprocess.PIPE, stderr=None).\
  communicate()[0].\
  replace('\n','')
print VAR

Tis awful for shell scripting too

Compare:

cat filename | grep -e 'a'
cat filename | sed -ne '/a/p'
cat filename | perl -ne '/a/&&print'
cat filename | perl -ne 'if(/a/){print}'
cat filename | perl -ne 'print if /a/'
cat filename | ruby -ne 'if $_.include? "a" then puts $_ end'
cat filename | python -c "for line in __import__('sys').stdin:^M  if 'a' in line:^M    print line,"
(Those are embedded newline characters, and the spaces are required.)

Range is inclusive/exclusive

I mean, really?

>>> for i in range(1,10):
...     print i
... 
1
2
3
4
5
6
7
8
9
>>> 

Hash implementation isn't very intelligent

>>> a={}
>>> a.update({"key1": "value1"})
>>> a.update({})
>>> a.update(None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not iterable

Dictionary syntax is inconsistent

>>> d={'one':1}
>>> print d{'one'}
  File "<stdin>", line 1
    print d{'one'}
           ^
SyntaxError: invalid syntax
>>> print d['one']
1

Loop implementation isn't very smart

>>> for x in None:
...     print "Yeap"
...
Traceback (most recent call last):
TypeError: 'NoneType' object is not iterable

None is a tragedy

Not only does None fail in general list context, as above, it prevents functions from reasonable behavior:
a, b = func(parameters)
TypeError: 'NoneType' object is not iterable
Every function that returns a list must therefore be called as some variation of:
result = func(parameters)
if result is not None:
  a, b = result
There are many different design approaches to work around this issue, but most are substandard compared to "populate the left hand side from the right hand side, as much as is possible".

Lists... aren't

#!/usr/bin/python

def test(*args):
  for i in args:
    print "a(%s)" % i

a={'hi': 'there', 'two': 2}
b={'good': 'bye'}
c=[1,2,3]

test('one', 'two', 'three', a.keys(), b.keys(), c)
Note that "a.keys()" is passed in as an array, not a list. This is silly since "[a.keys()]" can be used to create an array, but there's no technique to 'uncreate' an array. One can attempt the "*a" approach, but "*a, *b" won't work.

Printing is complicated

Let's print "hithere", supposing the output comes from two separate steps of our program:

print "hi"
print "there"

Oops, that didn't work. Let's try again.

print "hi",
print "there"

Um...

Regular expressions combine poorly

As with most languages that aren't Perl, and specifically languages that view regular expressions as complicated objects instead of a fundamental type, there are significant difficulties dealing with regular expressions as ``things''. Most regular expressions in Python and similar languages must be exhorbitantly simple, or you'll find yourself fighting with the objects to perform the most basic of tasks.

As an example, suppose it is necessary to match lines about certain types of fruit but, in some cases, to also match lines about those types of fruit being ``good''. Further suppose that the ``goodness'' match must follow the fruit match (so that this is not a Boolean OR, but an ordered, sequential match).

Here we go in Python. Note the complicate gyration required to use a compiled regex as a regex:

fruit = re.compile('apple|cherry|grape', re.I)
goodfruit = re.compile('(?:%s).*good' % fruit.pattern, re.I)

if goodfruit.search("apples are good"):
  print "Found good fruit"

Let us compare with Perl. Note how regular expression variables are utilized automatically:

$fruit=qr/apple|cherry|grape/i;
$goodfruit=qr/(?:$fruit).*good/i;

if("apples are good"=~/$goodfruit/) { print "Found good fruit\n" }

Regular expression substitutions are cumbersome

Given a string of multiple lines, suppose you wish to remove all whitespace from the beginning of every line in the string. In Python, you have to compile your regex if you wish to use flags:
import re
s = "  Multiline\n  string"
s = re.sub(re.compile('^\s*', re.MULTILINE), '', s)
print s

Let us compare with Perl.

$s="  Multiline\n  string";
$s=~s/^\s*//mg;
print "$s\n";
If one further argues, in good PEP8 style, that the Python should likely be split into a variable definition for the compiled pattern, coupled with a separate call to the substitution, that idiom becomes even more detached: Declare a pattern that matches the beginning of lines followed by any spaces; make it a multiline pattern; substitute, on any match of that pattern (don't forget that it's multiline!), replace with the empty string, and process the string 's' with that substitution. Ugh.

By comparison, Perl reads: Given string $s, substitute, for some spaces at the beginning of the line, the empty string; consider $s to be a multiline string, and replace all occurrences.

Set Syntax Silliness

The syntax for creating sets is not terribly intelligent:
>>> set('one','two')
Traceback (most recent call last):
TypeError: set expected at most 1 arguments, got 2
Well then, apparently we can't create a set of strings. Let's try to create a set from an array by reference:
>>> set(['one','two'])
That works, despite looking like a single-element set.

Now then, what actually happens with a single string?

>>> set('one')
set(['e','o','n'])
Well isn't that cute. That sure looks like it should be set('o','n','e') to me. Let's make sure it's consistent:
>>> set(123)
Traceback (most recent call last):
TypeError: 'int' object is not iterable
So a string is iterable but an integer isn't? Oh dear.

Now let's see if we can keep a set of references to a list

>>> b=[1,2,3]
>>> m=set(b)
>>> print b in m
Traceback (most recent call last):
TypeError: unhashable type: 'list'
It's too bad that variables in Python aren't references or values but references to values. Oh well.

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]