My newbie annoyances so far

P

Paul McGuire

Python is not VB and Python is not Java and Python is not Ruby and
Python is not any other language that is not Python.

1. Functions cannot be called without the parens (like in VB)

2. Python uses some naming conventions as programmer cues, such as
leading and trailing double-underscores to indicate some form of
specialness (I'm not overfond of relying on naming for this kind of
information encoding either, but I got used to it)

3. Python does not use braces to demarcate executable blocks of code,
or to define anonymous code blocks (like in Java, Ruby, or Smalltalk)

4. Python does not require every line of code to be enclosed within a
class (like in Java or Smalltalk)

5. Python does not do compile-time type checking on function arguments
or variable assignments (like in Java or C or C++) (yet... and will it
still be Python when it does?)

6. Python does not have interfaces to enforce object type
compatibility (like in Java)

Just because Python has features that are different from those in your
former language X does not mean it is deficient. Python *might* be
deficient - ternary expressions are now part of the language after
years of refugees from C and C++ asking how to write "a = b ? c : d",
and now they'll get to puzzle/gripe over mapping this to "a = c if b
else d". But as a newbie, you need to invest a little more time and
effort and study and reflection (collectively called "experience")
before bandying about lists of personal gripes and reasons why Python
is annoying/stupid/sucks. At least in public. Actually, it might be
of value to keep your own personal list, and then revisit it a month
or a year later and see if the warts are still as offending to your
sensibilities as they originally were.

Newbies, please try to work with Python as it is for a bit. Ask
questions when the documentation is unclear to you or the results of
your efforts confound you. But please hold of on the "reasons Python
sucks" lists. You might find that these "deficiencies" actually
translate into strengths. Despite its warts, Python is being used
productively by at least several dozen people around the world, so it
must be good for *something*.

-- Paul
 
J

John Nagle

Paul said:
Python is not VB and Python is not Java and Python is not Ruby and
Python is not any other language that is not Python.

As someone who's written in too many programming languages over
a long career, I'm quite pleased with Python as a programming
language. It's straightforward to write, has few irregularities,
and has good run-time error semantics.

The weak points in Python are implementation issues.
Sockets, HTTP access, SSL, and database access are all
flakier than they should be for such common capabilities.
The CPython implementation is unreasonably slow compared
to good implementations of other dynamic languages such
as LISP and JavaScript.

But really, the language is in good shape. I'd rather
have a faster implementation of Python 2.5 than anything
being proposed as a language change.

John Nagle

(P.S. PEP 3117 is a joke, right?)
 
D

Dennis Lee Bieber

deficient - ternary expressions are now part of the language after
years of refugees from C and C++ asking how to write "a = b ? c : d",
and now they'll get to puzzle/gripe over mapping this to "a = c if b
else d". But as a newbie, you need to invest a little more time and

And I'll probably ignore those expressions whenever I do get around
to 2.5+... That syntax, in my mind, just... stinks...

HP RPL made more sense: b if c [else d] end

--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
J

John Nagle

Dennis said:
And I'll probably ignore those expressions whenever I do get around
to 2.5+... That syntax, in my mind, just... stinks...

ALGOL used "expression IF"; you could write

x := (IF a > b THEN a ELSE b);

but that doesn't map well to an indentation-based language.

A syntax suitable for Python, now that there's a bool type, might
be to define ".if()" for "bool". Then one could write

(a > b).if(a,b)

which is better than adding an operator.

Such things are useful in formatting expressions.

msg = 'Unit is %s' % (unitstatus.if("on","off"),)

but not really essential.

John Nagle
 
P

Paul McGuire

ALGOL used "expression IF"; you could write

x := (IF a > b THEN a ELSE b);

but that doesn't map well to an indentation-based language.

A syntax suitable for Python, now that there's a bool type, might
be to define ".if()" for "bool". Then one could write

(a > b).if(a,b)

which is better than adding an operator.

Such things are useful in formatting expressions.

msg = 'Unit is %s' % (unitstatus.if("on","off"),)

but not really essential.

John Nagle

I think a big part of the current syntax is that it still supports
short-circuiting. In

x if a else y

y never has to be evaluated if condition a is true. When calling
a.if(x,y), both x and y have to be evaluated.

-- Paul
 
B

Bjoern Schliessmann

Dennis said:
And I'll probably ignore those expressions whenever I do get
around to 2.5+... That syntax, in my mind, just... stinks...

HP RPL made more sense: b if c [else d] end

Please explain.

HP RPL: b if c [else d] end
Python: b if c else d

What's the "more sense" here?

Regards,


Björn
 
M

Marc 'BlackJack' Rintsch

Dennis said:
HP RPL made more sense: b if c [else d] end

Please explain.

HP RPL: b if c [else d] end
Python: b if c else d

What's the "more sense" here?

The HP RPL leaves even more questions. If the square brackets mean the
``else`` part is optional, what would be the result of the expression if
`c` is `False`?

Hypothetical HP RPL syntax construct in Python::

x = 42 if False end
print x # -> ???

Ciao,
Marc 'BlackJack' Rintsch
 
D

Dennis Lee Bieber

Dennis said:
And I'll probably ignore those expressions whenever I do get
around to 2.5+... That syntax, in my mind, just... stinks...

HP RPL made more sense: b if c [else d] end

Please explain.

HP RPL: b if c [else d] end
Python: b if c else d

What's the "more sense" here?
You didn't take account of what b, c, and d were...

RPL: <condition> if <truth> else <false> end
Python: <truth> if <condition> else <false>

(RPL is a somewhat common reference to the stack based language of the
later calculators -- HP48, for instance)
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
S

Steven D'Aprano

Dennis said:
And I'll probably ignore those expressions whenever I do get
around to 2.5+... That syntax, in my mind, just... stinks...

HP RPL made more sense: b if c [else d] end

Please explain.

HP RPL: b if c [else d] end
Python: b if c else d

What's the "more sense" here?
You didn't take account of what b, c, and d were...

RPL: <condition> if <truth> else <false> end
Python: <truth> if <condition> else <false>

(RPL is a somewhat common reference to the stack based language of the
later calculators -- HP48, for instance)

I believe RPL is the official name of the language used for the HP-28 and
-48 series calculators, although it doesn't appear to be in their
reference manuals.

The syntax as given above is actually incorrect. That appears more like
Forth -- an easy mistake to make. In RPL, it is:

IF <test-clause> THEN <true-clause> END
IF <test-clause> THEN <true-clause> ELSE <false-clause> END

Note that despite being a stack-based language, the Reverse Polish
notation of RPL is loosened slightly for conditional and looping commands.
The syntax above is a little misleading... in fact, IF doesn't actually do
anything (but is required!), as it is the THEN that pops a flag off the
stack. So long as there is a value on the stack for the THEN to pop off,
it doesn't matter if it gets there before or after the IF. Hence many
people preferred to write:

<test-clause> IF THEN <true-clause> ELSE <false-clause> END

instead. Note also that each <*-clause> can be a block of code, and is
only executed if needed. Either true-clause or false-clause can be empty.
 
B

Bjoern Schliessmann

Dennis said:
You didn't take account of what b, c, and d were...

RPL: <condition> if <truth> else <false> end
Python: <truth> if <condition> else <false>

(RPL is a somewhat common reference to the stack based language of
the later calculators -- HP48, for instance)

I still don't see the "more sense". Python's variant seems logical
to me -- "<fetch out garbage> if <garbage can full> else <don't>".

The HP equivalent will be, if I understand correctly:

"<garbage can full> if <fetch out garbage> [else <don't>]"

I see two problems here:

- Also from my error in the last posting it's quite clear that the
RPL statement doesn't do what one would suppose. Isn't this what
Python always tries to avoid: Doing something different from what
is "obvious". RP order doesn't fit in Python, IMHO.

- What should the expression's value be if the else is omitted?
None? What's it in the original? I can't imagine a use case here
since I always have two alternatives when I use "a if b else c".

Regards,


Björn
 
S

Steven D'Aprano

Dennis said:
You didn't take account of what b, c, and d were...

RPL: <condition> if <truth> else <false> end
Python: <truth> if <condition> else <false>

(RPL is a somewhat common reference to the stack based language of
the later calculators -- HP48, for instance)

I still don't see the "more sense". Python's variant seems logical
to me -- "<fetch out garbage> if <garbage can full> else <don't>".

The HP equivalent will be, if I understand correctly:

"<garbage can full> if <fetch out garbage> [else <don't>]"

As I explained in another post, the syntax given is wrong for RPL, but if
it were right, then that description would be correct: the if would pop a
flag off the stack, in this case <garbage can full>, and then branch to
I see two problems here:

- Also from my error in the last posting it's quite clear that the
RPL statement doesn't do what one would suppose.

There are bad programmers in every language, but RPL conditional blocks
aren't the cause of them. Once you learn how RPL works, if statements work
consistently and obviously (although maybe not to programmers who don't
get RP notation).

Isn't this what
Python always tries to avoid: Doing something different from what
is "obvious". RP order doesn't fit in Python, IMHO.

I agree that blindly trying to copy RP notation into Python wouldn't work.

- What should the expression's value be if the else is omitted?
None? What's it in the original? I can't imagine a use case here
since I always have two alternatives when I use "a if b else c".

In RPL, there are no expressions. RPL programs are constructed from data
and commands, not expressions. So you shouldn't think of

<garbage can full> if <fetch out garbage> [else <don't>]

as an expression. Think of it as a block, equivalent to the Python:

if garbage_can_full:
fetch
out
garbage
else:
don't

except that you can write it as a single line. Newlines in RPL are just
another sort of whitespace, with no special significance.

If the else clause is missing, then nothing is executed and processing
simply continues past the end of the block.

I agree with you that in the case of Python _expressions_, it doesn't make
sense to have a missing else part. But in the case of RPL, it is perfectly
natural for the else block to be missing.
 
D

Dennis Lee Bieber

The HP RPL leaves even more questions. If the square brackets mean the
``else`` part is optional, what would be the result of the expression if
`c` is `False`?
Stack based calculator language -- if no else part, nothing gets put
on the stack...
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
B

Bjoern Schliessmann

Steven said:
There are bad programmers in every language, but RPL conditional
blocks aren't the cause of them. Once you learn how RPL works, if
statements work consistently and obviously (although maybe not to
programmers who don't get RP notation).

ACK. What made me anwswer wasn't RPL (after all I use an RPN
calculator ;) ), but the statement that it were "more logic" than
Python's "classic" infix logic.
In RPL, there are no expressions. RPL programs are constructed
from data and commands, not expressions. So you shouldn't think of

<garbage can full> if <fetch out garbage> [else <don't>]

as an expression. Think of it as a block, equivalent to the
Python:

if garbage_can_full:
fetch
out
garbage
else:
don't

except that you can write it as a single line. Newlines in RPL are
just another sort of whitespace, with no special significance.

If the else clause is missing, then nothing is executed and
processing simply continues past the end of the block.

That made it clear, thanks.

Regards,


Björn
 
I

igouy2

The CPython implementation is unreasonably slow compared
to good implementations of other dynamic languages such
as LISP and JavaScript.

Why do you say CPython is slower than JavaScript? Please provide
examples.
 
J

John Nagle

Why do you say CPython is slower than JavaScript? Please provide
examples.

See

http://www.mozilla.org/projects/tamarin/faq.html

Tamarin is a just-in-time compiler for Javascript.

Franz LISP at one time held the speed record for LISP
implementations, being only slightly slower than C.

Python is generally considered to be about 60x slower
than C, which is about par for the course for a naive
byte code interpreter.

John Nagle
 
A

Alex Martelli

John Nagle said:
See

http://www.mozilla.org/projects/tamarin/faq.html

Tamarin is a just-in-time compiler for Javascript.

....and is not yet released, as far as I can tell; this makes it kind of
diffcult to verify any kinds of claims about its speed. So, I tried to
check the current speed of actual, existing, released open-source
stand-alone Javascript engines -- starting with Mozilla's own
"spidermonkey" -- versus the CPython implementation which you claim is
"unreasonably slow".

I set myself a simple benchmark which I thought would be impartial (AKA
"equally unfair to both sides":) because it's a pretty weird task, for
which neither engine has definitely been optimized: find out what pair
(number-of-vowels, number-of-consonants) happens most often among the
words in /usr/share/dict/words (the one I have on my Macbook Pro: the
wordlist from Webster's Second International, 1934 edition). I ran into
a few snags tied to me not being a particularly good Javascript
programmer, and to limitations of the spidermonkey js that I could
easily install (via MacPorts): no file I/O support (except for
stdin/stdout), so the input has to come from stdin -- etc, etc; I tried
making things fair by placing the same limitations on each
implementation (also forcing Python to use stdin, etc).

I'm sure my Javascript code can be made much better, but here is what I
have so far, as a.js:


var vowels_re = /[aeiou]/gi;
var conson_re = /[bcdfghjklmnpqrstvwxyz]/gi;
var v_w_count = new Object;
while (1) {
var x = readline();
if (x=='' || x==null) {
break;
}
var vows = x.match(vowels_re);
var numvows = (vows==null)?0:vows.length;
var cons = x.match(conson_re);
var numcons = (cons==null)?0:cons.length;
var key = 100*numvows + numcons;
v_w_count[key] = 1 + (v_w_count[key] || 0);
}
var topcombo = 0;
var maxcount = 0;
for (key in v_w_count) {
var newcount = v_w_count[key];
if (newcount > maxcount) {
maxcount = newcount;
topcombo = key;
}
}
var nc = topcombo % 100;
var nv = (topcombo-nc) / 100;
print("top combination: "+nv+" vowels, "+nc+" consonants (occurs
"+maxcount+" times).");


and the result and timing:

$ time js -f a.js </usr/share/dict/words
top combination: 3 vowels, 5 consonants (occurs 14947 times).

real 0m18.664s
user 0m12.717s
sys 0m0.370s


Here's the Python equivalent, a.py -- with the same constraints about
having to use REs for the vowel/consonant counting, stdin-only, etc:

$ time python a.py </usr/share/dict/words
top combination: 5 vowels, 3 consonants (occurs 14947 times).

real 0m3.700s
user 0m2.814s
sys 0m0.869s

I'm sure that Tamarin, _once it's released_, will vastly enhance
Javascript's current mediocre showing. But, for now, it appears to
border on the dishonest to claim that CPython is unreasonably slow
compared to _existing_ implementations of Javascript (and it would
obviously be _totally_ dishonest to compare existing implementations
with "paper tiger" ones that are _not_ yet existing and released).


The fact that this is not a task for which Python is especially
optimized, btw, can be confirmed by comparing Python's timing with an
equivalent C-coded program with the same restrictions (using pcre):

#include <pcre.h>
#include <string.h>
#include <stdio.h>

int re_count(char* st, pcre* re)
{
int ovec[3];
int count = 0;
int len = strlen(st);
int start = 0;
int rc;
while( (rc=pcre_exec(re, NULL, st, len, start, 0, ovec, 3)) >= 0)
{
count++;
start = ovec[1];
}
if (rc != PCRE_ERROR_NOMATCH) {
printf("rc was %d\n", rc);
}
return count;
}

int store_counts[100*100];
void add_count(int nc, int nv) {
store_counts[nc + 100*nv]++;
}
int max_count(int* nc, int* nv) {
int bestloc = 0;
int topcoun = 0;
int i;
for(i=0; i<100*100; i++) {
if (store_counts > topcoun) {
bestloc = i;
topcoun = store_counts;
}
}
*nc = bestloc % 100;
*nv = bestloc / 100;
return topcoun;
}

int main()
{
const char* errms;
int erof;
pcre* vowels_re = pcre_compile("[aeiou]",
PCRE_CASELESS, &errms, &erof, NULL);

if (!vowels_re) {
printf("(%s) at (%d) on vowels\n", errms, erof);
return 1;
}
pcre* conson_re = pcre_compile("[bcdfghjklmnpqrstvwxyz]",
PCRE_CASELESS, &errms, &erof, NULL);
if (!conson_re) {
printf("(%s) at (%d) on conson\n", errms, erof);
return 1;
}
char buffer[1000];
while (gets(buffer)) {
int nv = re_count(buffer, vowels_re);
int nc = re_count(buffer, conson_re);
add_count(nv, nc);
}
int pnv, pnc, maxc;
maxc = max_count(&pnv, &pnc);

printf("top combination: %d vowels, %d consonants (occurs %d
times).\n",
pnv, pnc, maxc);

return 0;
}

$ time ./a.out </usr/share/dict/words
warning: this program uses gets(), which is unsafe.
top combination: 3 vowels, 5 consonants (occurs 14947 times).

real 0m0.673s
user 0m0.635s
sys 0m0.012s


We do observe the typical ratio in runtimes -- about 5.35 in this case
(around one order of magnitude is typical).

Of course, it's easy to enhance these performances by doing away with
regular expressions -- e.g., in Python, b.py:

import string

identity = string.maketrans('', '')
def make_counter(lower_string):
total_string = lower_string + lower_string.upper()
def counter(s, ident=identity, thest=total_string):
return len(s) - len(s.translate(ident, thest))
return counter

def main(afile):
count_vowels = make_counter('aeiou')
count_conson = make_counter('bcdfghjklmnpqrstvwxyz')
v_w_count = {}
for line in afile:
nv = count_vowels(line)
nc = count_conson(line)
key = nv, nc
v_w_count[key] = 1 + v_w_count.get(key, 0)
top = max(v_w_count, key=v_w_count.get)
nc = top[0]
nv = top[1]
n = v_w_count[top]
print "top combination:", nv, "vowels,", nc, "consonants (occurs",
n, "times)."

if __name__ == '__main__':
import sys
main(sys.stdin)

easily speeds things up by over 3.5 times:

$ time python b.py </usr/share/dict/words
top combination: 5 vowels, 3 consonants (occurs 14947 times).

real 0m1.045s
user 0m0.976s
sys 0m0.061s

and a similar speedup can be had in C (also by eliminating the use of
REs), e.g.:

#include <string.h>
#include <stdio.h>

char * vowels = "aeiouAEIOU";
char * conson = "bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ";
void count_letters(char* astr, int* pnv, int* pnc) {
int c;
int nv=0;
int nc=0;
while(c = *astr++) {
if(strchr(vowels, c)) nv++;
else if(strchr(conson, c)) nc++;
}
*pnv = nv;
*pnc = nc;
}

int store_counts[100*100];
void add_count(int nc, int nv) {
store_counts[nc + 100*nv]++;
}
int max_count(int* nc, int* nv) {
int bestloc = 0;
int topcoun = 0;
int i;
for(i=0; i<100*100; i++) {
if (store_counts > topcoun) {
bestloc = i;
topcoun = store_counts;
}
}
*nc = bestloc % 100;
*nv = bestloc / 100;
return topcoun;
}

int main()
{
char buffer[1000];
while (gets(buffer)) {
int nv, nc;
count_letters(buffer, &nv, &nc);
add_count(nv, nc);
}
int pnv, pnc, maxc;
maxc = max_count(&pnv, &pnc);

printf("top combination: %d vowels, %d consonants (occurs %d
times).\n",
pnv, pnc, maxc);

return 0;
}


None of these sources is "super-optimized" (in particular, I'm sure it's
just as easy to make the Javascript 3-4 times faster as it was for
Python and C, if I only knew Javascript better -- but even the faster
Python and C programs could well be pushed further), but I think that
exactly because of this factor they may be "representative" of typical
uses of the languages (inasmuch as a tiny benchmark can ever be
"representative", of course).


Alex
 
J

John Nagle

Alex said:
...and is not yet released, as far as I can tell; this makes it kind of
diffcult to verify any kinds of claims about its speed.

Tamarind is inside the current implementation of Flash, but it's
not into Firefox yet, apparently. The current SpiderMonkey implementation
is nothing to get excited about in terms of performance.

My point is that there are optimizing hard-code compiler implementations
of many dynamic languages, including LISP, Self, and Smalltalk, but not Python.

John Nagle
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,233
Members
46,820
Latest member
GilbertoA5

Latest Threads

Top