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