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. Get it now!