More random python observations from a perl programmer

Duncan Booth duncan at rcp.co.uk
Thu Aug 19 12:37:50 EDT 1999


tchrist at mox.perl.com (Tom Christiansen) wrote in 
<37bc1339 at cs.colorado.edu>:
>GOTCHA: (medium)
>    The whole mutability versus immutability thing causes many 
>    confusions.
Yup, powerful but confusing at first.


>GOTCHA: (medium)
>    If you have a function that expects two arguments, such as:
>     def fn(x,y):
>         return x + y
>    and you have a tuple of the two elements:
>     t = (1,2)
>    You can't just call that function:
>     print fn(t)
>    Or you get a "TypeError: not enough arguments; expected 2, got 1"
>    error.  You have to use this apply() function to get around this
>    issue:
>     print apply(fn,t)
>     3
Or if you know you are going to have a tuple, you could declare the 
function to take a tuple as its argument:
def fn((x,y)): ...

>GOTCHA: (low) 
>    There are no compound assignment operators, like +=.
We would have to reach agreement first on what += actually meant, and that 
doesn't seem to be happening for all the number of times it has been 
discussed.


>GOTCHA: (low)
>    Single and double quoted strings can't cross line boundaries.
>    You need triple quotes for that!
I would put this one under COOLNESS.

>DISSIMILARITY:
>    Because there are no variable markers in Python, there are no 
>    variable interpolation in strings.  That makes something like
>     print "this $x is $y here\n" 
>    become in python
>     print "this %d is %d here\n" % (x, y)

You didn't mention the alternative way of writing this which is possibly 
nearer the Perl version:
print "this %(x)s is %(y)s here\n" % {'x': x, 'y': y}

>GOTCHA: (high)
>    Python has no manpages!  The horror!!!!!!!!!!!!!!!!!!!!!!
>    ENODOC
Python has loads and loads of documentation.

>GOTCHA: (medium)
>    All ranges are up to but *not including* that point.  So range(3)
>    is the list [0,1,2].  This is also true in slices, which is the
>    real gotcha part.  A slide t[2:5] does not include t[5] in it.
I think this is necessary to allow all of the variations on slicing. For 
example to insert between elements of a list.
    	x = [1, 2, 3]
    	x[1:1] = [5]
    	print x
    	[1, 5, 2, 3]

>GOTCHA: (high)
>    This is a big surprise: strings are not atomic (although they are
>    immutable).
>     >>> for c in ("weird", "bits"):

>     >>> for c in ("weird"):
For consistency with the first example you need
>>> for c in ("weird",)

However I agree it can be confusing that when you subscript a string you 
get another object of type string.

>GOTCHA: (high)
>    As we saw with lists, because everything is a reference, and there's
>    no way to dereference that reference, this means that again there
>    is also no built-in, intuitive way to copy a dictionary.  Instead, 
>    the suggested work-around is to write a loop:
>     new = {}
>     for key in old.keys:
>         new[key] = old[key]
My suggested way to copy a dictionary is:
    	new = old.copy()
Or, if you want to copy all the elements as well:
    	from copy import deepcopy
    	new = deepcopy(old)

>    But this is guaranteed slower, because it's not at the C level.
The copy method and functions are at the C level.

>    It also shows that dictionaries aren't first class citizens in python
>    as they are in Perl:
I think there is a fundamental misunderstanding here. Variables in python 
are always references. They never copy the value they point to when 
assigned. You could equally say that this means that integers are not first 
class citizens because:
    	x = 1
    	y = x
leaves x and y pointing at the same object (x is y) is true.
    	
>
>GOTCHA: (high)
>    Lists don't autoallocate the way dictionaries do.  So while this works
>    on two dictionaries:
>     new = {}
>     for key in old.keys:
>         new[key] = old[key]
>    This fails on two lists:
>     new = []
>     for i in old:
>         new[i] = old[i]
This is meaningless and nothing to do with autoallocating. i is iterating 
over values not indexes. you get the effect you want here by writing
    	for i in old:
    	    	new.append(i)

>GOTCHA: (medium)
>    Importing a variable only gives you a local copy.  In Perl, it makes
>    two names for the same object.
No, importing just gives you two names for the same object just as 
assignment only ever gives you two names for the same object. Of course if 
you later reassign one of the names to point to a different object the two 
variables no longer have the same value.

>GOTCHA: (high)
>    Because you can't use readline() to get a number, people seem to enjoy
>    calling eval() just to get a string turned into a number:
>     import sys
>     str = sys.stdin.readline()
>     num = eval(x)
>    This is scary.  Even scarier is the propensity for calling input(),
>    which auto-eval()s its input to make sure it's the right "type".
>    (Funny that a soi-disant "typeless language" should be so danged
>    picky about this.)  That means you see people write:
>     num = input("Pick a number? ")
>    But the person can supply as an answer 0x23 or 2+9 or pow(2,4)
>    or os.system("rm -rf *").  I am stunned.

People may enjoy this but personally I would just do
    	num = int(sys.stdin.readline())
BTW, I am not commenting on the comparisons with Perl since I don't claim 
to know that language, but I seem to remember hearing that Perl would 
silently convert the string "42x" into the number 42 without throwing an 
error, now there is scary.

>GOTCHA: (low)
>    Regexes default to emacs style, not egrep style!  Gads!  This is
>    surprising to anyone except an emacs weenie.  Sigh.  And just *try*
>    to read the manpage on the differences based on passed in arguments
>    establishing the style.  There aren't any manpages!  Have a nice day.
Try reading the manual page doc/lib/re-syntax.html in your python 
distribution.


>GOTCHA: (low)
>    Normally, a print statement in python adds a newline.  If you
>    don't want one, you need a trailing comma!
Or use the write method of the file which doesn't do any of the print 
prettifying.

>GOTCHA: (medium)
>    Anything that python doesn't like, it raises an exception about.
>    There is no fail-soft.  Even non-exception issues raise exceptions.
>    It's pervasive.  K&P curse languages that force people who want
>    to open() a file to wrap everything in exception code, saying that
>    "failing to open a file is hardly exceptional".  
I love this. But thats just me.

>
>GOTCHA: (medium)
>    You can't just interchange tuples and lists in python the way
>    you can lists and arrays in Perl.
Or the way you can interchange strings and numbers in Perl.
They are different types. (Why we need two list types is another question 
though).

>GOTCHA: (low)
>    You have to compiled the definition for a  function before you may
>    compile the call it.
Not true, you have to compile the definition for a function before you may 
execute the call to it. You may compile the call before the function if you 
wish.

>    ADDENDA: It turns out that def() happens *AT RUN TIME* in python.
>    That's the root of this problem.  In Perl, a sub{} is a compile-time
>    thing.
Dont forget that in Python you can stick your def in a for loop to define a 
whole host of functions with different default arguments.

Thanks for the article though, it made good reading.
(BTW if anyone flames me for getting bits of this wrong don't expect a 
reply soon because I'm away for two weeks).





More information about the Python-list mailing list