I'm sure you've heard most/all of this before but..it..just..seems..so..true...
Finally this week I've "written" (ported from sh) a bunch of Perl, 2000 sparse lines. While it sure beats Perl, it has some glaring flaws, more glaring due to its overall goodness.
I feel compelled to voice my opinion, as if we don't live in a benevolent dictatorship :), and as if the weight of existing code was zero. Much of what I dislike cannot be changed without massive breakage.
Below is what i get from:
jbook:/dev2/cm3/scripts/python/flaws jay$ ls -l total 72 -rw-r--r-- 1 jay admin 834 Dec 29 16:02 1_not_lexically_scoped.py -rw-r--r-- 1 jay admin 238 Dec 29 16:02 2_reads_scoped_writes_not.py -rw-r--r-- 1 jay admin 593 Dec 29 16:02 3_lambda_is_neutered.py -rw-r--r-- 1 jay admin 377 Dec 29 16:03 4_assignment_is_not_expression.py -rw-r--r-- 1 jay admin 760 Dec 29 16:02 5_for_loop_off_by_one.py -rw-r--r-- 1 jay admin 412 Dec 29 16:01 6_docs_good_but_a_complaint.txt -rw-r--r-- 1 jay admin 254 Dec 29 16:02 7_print_is_wierd.py -rw-r--r-- 1 jay admin 286 Dec 29 16:06 8_eval_vs_exec.py -rw-r--r-- 1 jay admin 824 Dec 29 16:14 9_typo_on_read_error_but_write_ok.py
jbook:/dev2/cm3/scripts/python/flaws jay$ cat * > all.txt
jbook:/dev2/cm3/scripts/python/flaws jay$ edit all.txt
Each "---" seperates a file and they are executable Python.
- Jay
#---------------------------------------------------------- # flaw #1 # not lexically scopied # Functions have their own locals, but other blocks do not. # This is true both for "normal" variables and lexically nested functions. #
# # This is probably largely an outcome of not declaring variables? #
A = "A1:global"
def F1(): A = "A1:in first F1" print "F1:global"
if True: A = "A1:in if" def F1(): A = "A1:in if.F1" # This does the right thing. print "F1:in if" F1() # This does the right thing.
# This should go to "global" but it goes to "in if" F1()
def F2(): A = "A1:in F2" def F1(): A = "A1:in F2.F1" print "F1:in F2"
# Given how if behaved, you'd expect this to go to F2.F1 but it does not. F1()
# This should be "global" but is "in if". print("A is " + A)
#---------------------------------------------------------- # flaw #2 # # In functions, reads are scoped. Writes are not. #
A = "1"
def F1(): A = "2" # not an error
def F2(): #B = A # error A = "3"
F1() F2() print(A)
#---------------------------------------------------------- # flaw #3: # lambda is neutered # It allows just one expression, and no statements #
# This should work:
import os
#os.path.walk( # "..", # lambda(a, b, c): # print(b) # print(b) # None)
# Instead I must say:
def Callback(a, b, c): print(b) print(b)
os.path.walk( "..", Callback, None)
# # Moving callbacks away from their point of use hurts readability. # This is probably mitigated by lexical scoping of functions, but # notice that other blocks are not lexically scoped. #
#---------------------------------------------------------- # flaw #4: # assignment is not an expression #
# This should work (seen in Perl code, nice idiom):
#A = [1,2] #while (B = A.pop()): # print(B)
# instead I must say:
A = [1,2] while (A): B = A.pop() print(B)
# Even if you reject popping an empty list, ok # there are PLENTY of applications of this.
#---------------------------------------------------------- # flaw #5 # # for loops suck # # It should be easy to iterate from 0 to n, not 0 to n - 1, # thereby knowing why the loop terminated #
#This should work:
# print the first even number, if there are any
A = [1, 3] for i in range(0, len(A)): if ((A[i] % 2) == 0): print("even number found") break; if (i == len(A)): print("no even numbers found")
# instead I must write:
i = 0 while (i != len(A)): if ((A[i] % 2) == 0): print("even number found") break; i += 1 if (i == len(A)): print("no even numbers found")
# with the attendent problem of not being able to "continue" ever, since # the end of the loop body must be run in order to proceed
Flaw #6
The docs are very good.
However the reference doesn't give much in the way of semantic description.
It is surprising that an experienced programmer MUST depend on the tutorial or any examples or semantics. Light on examples, ok for reference.
The language reference is little more than the grammar in parts.
There needs to be links from the reference back to the tutorial.
Perhaps merge the indices for Tutorial, Language Reference, Library Reference. Or maybe that's what search is for.
On the other hand, way better than Perl.
#---------------------------------------------------------- # Flaw #7 # # This is a compatibility issue. # print is both a statement and a function, or something. #
print() # should print just a newline, but prints two parens
# workaround:
print("")
#---------------------------------------------------------- # flaw #8 # # Having to eval expressions but exec statements feels wrong. # There should just be eval. #
# eval("print(1)") # error exec("print(1)") # not an error
exec("1 + 2") # not an error? eval("1 + 2") # not an error
#---------------------------------------------------------- # flaw #9 # # Python protects me, via early checking, from typos # when I read, but not when I write. It should do both. # That is, I should declare variables. #
Correct = 1 # proposed typo is Corect
#A = Corect # error, good Corect = 1 # no error, bad
# For classes, by default, same thing:
class Foo(object): def __init__(self): self.Correct =1
F = Foo() # print(F.Corect) # error, good F.Corect = 1 # no error, bad
# __slots__ fixes this, but is not the default
class Bar(object): __slots__ = ["Correct"] def __init__(self): self.Correct =1
B = Bar() # print(B.Corect) # error, good #B.Corect = 1 # error, good
# __slots__ should be the default and then some other syntax # for "expandable" types, like __slots__ = [ "*" ]
_________________________________________________________________ Get the power of Windows + Web with the new Windows Live. http://www.windowslive.com?ocid=TXT_TAGHM_Wave2_powerofwindows_122007
Jay schrieb:
Only addressing the easier points here:
#---------------------------------------------------------- # flaw #2 # # In functions, reads are scoped. Writes are not. #
A = "1"
def F1(): A = "2" # not an error
def F2(): #B = A # error A = "3"
F1() F2() print(A)
"Writes" creates a new local. If you want to modify the enclosing binding, the new "nonlocal" statement in 2.6/3.0 will enable that.
#---------------------------------------------------------- # flaw #3: # lambda is neutered # It allows just one expression, and no statements
Lambda can't be altered to allow statements *and* have a consistent indentation-based syntax.
#---------------------------------------------------------- # flaw #5 # # for loops suck # # It should be easy to iterate from 0 to n, not 0 to n - 1, # thereby knowing why the loop terminated #
#This should work:
# print the first even number, if there are any
A = [1, 3] for i in range(0, len(A)): if ((A[i] % 2) == 0): print("even number found") break; if (i == len(A)): print("no even numbers found")
The for loop has an else clause.
for x in A: if x % 2 == 0: print "even number found" break else: print "no even numbers found"
Flaw #6
The docs are very good.
However the reference doesn't give much in the way of semantic description.
It is surprising that an experienced programmer MUST depend on the tutorial or any examples or semantics. Light on examples, ok for reference.
The language reference is little more than the grammar in parts.
There needs to be links from the reference back to the tutorial.
Perhaps merge the indices for Tutorial, Language Reference, Library Reference. Or maybe that's what search is for.
Look at the new docs for 2.6 -- there's many more references in it. http://docs.python.org/dev
#---------------------------------------------------------- # Flaw #7 # # This is a compatibility issue. # print is both a statement and a function, or something.. #
print() # should print just a newline, but prints two parens
# workaround:
print("")
print is a statement, and no function. () is an empty tuple, so "print ()" prints an empty tuple. (""), on the other hand, is the same as "".
#---------------------------------------------------------- # flaw #8 # # Having to eval expressions but exec statements feels wrong. # There should just be eval. #
# eval("print(1)") # error exec("print(1)") # not an error
exec("1 + 2") # not an error? eval("1 + 2") # not an error
There's a clear distinction between expressions and statements, so it makes sense here too.
cheers, Georg
It would make more sense to redirect "criticism" out of beginners' ignorance to comp.lang.python rather than spend time discussing their misunderstandings here.
On Jan 13, 2008 9:28 AM, Georg Brandl g.brandl@gmx.net wrote:
Jay schrieb:
Only addressing the easier points here:
#---------------------------------------------------------- # flaw #2 # # In functions, reads are scoped. Writes are not. #
A = "1"
def F1(): A = "2" # not an error
def F2(): #B = A # error A = "3"
F1() F2() print(A)
"Writes" creates a new local. If you want to modify the enclosing binding, the new "nonlocal" statement in 2.6/3.0 will enable that.
#---------------------------------------------------------- # flaw #3: # lambda is neutered # It allows just one expression, and no statements
Lambda can't be altered to allow statements *and* have a consistent indentation-based syntax.
#---------------------------------------------------------- # flaw #5 # # for loops suck # # It should be easy to iterate from 0 to n, not 0 to n - 1, # thereby knowing why the loop terminated #
#This should work:
# print the first even number, if there are any
A = [1, 3] for i in range(0, len(A)): if ((A[i] % 2) == 0): print("even number found") break; if (i == len(A)): print("no even numbers found")
The for loop has an else clause.
for x in A: if x % 2 == 0: print "even number found" break else: print "no even numbers found"
Flaw #6
The docs are very good.
However the reference doesn't give much in the way of semantic description.
It is surprising that an experienced programmer MUST depend on the tutorial or any examples or semantics. Light on examples, ok for reference.
The language reference is little more than the grammar in parts.
There needs to be links from the reference back to the tutorial.
Perhaps merge the indices for Tutorial, Language Reference, Library Reference. Or maybe that's what search is for.
Look at the new docs for 2.6 -- there's many more references in it. http://docs.python.org/dev
#---------------------------------------------------------- # Flaw #7 # # This is a compatibility issue. # print is both a statement and a function, or something.. #
print() # should print just a newline, but prints two parens
# workaround:
print("")
print is a statement, and no function. () is an empty tuple, so "print ()" prints an empty tuple. (""), on the other hand, is the same as "".
#---------------------------------------------------------- # flaw #8 # # Having to eval expressions but exec statements feels wrong. # There should just be eval. #
# eval("print(1)") # error exec("print(1)") # not an error
exec("1 + 2") # not an error? eval("1 + 2") # not an error
There's a clear distinction between expressions and statements, so it makes sense here too.
cheers, Georg
-- Thus spake the Lord: Thou shalt indent with four spaces. No more, no less. Four shall be the number of spaces thou shalt indent, and the number of thy indenting shall be four. Eight shalt thou not indent, nor either indent thou two, excepting that thou then proceed to four. Tabs are right out.
Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/guido%40python.org