More random python observations from a perl programmer

Thomas Wouters thomas at xs4all.nl
Thu Aug 19 17:48:00 CEST 1999


On Thu, Aug 19, 1999 at 08:22:49AM -0700, Tom Christiansen wrote:

> This article was posted to the Perl newsgroup, but I have duplicated
> the posting here without crossposting to avoid flame wars.

Sorry, i have to reply. I wont mention much, and i definately dont want to
start a flame war (i use perl about as often as python, but python fits my
soul, perl does not.)

> GOTCHA: (low)
>     You can't use "in" on dicts.  Instead, you must use 
> 	d = { "fred":"wilma", "barney":"betty" }
> 	if d.has_key("fred"):	# legal
> 	if "fred" in d:	        # ILLEGAL
>     I don't understand why this was done.

It's an extension of Python's setup. Not everything is done to be immediately
obvious, but everything is done to be _consistent_, and instantly obvious if
you understand python. The 'in' statement works sort of like the pseudocode:

index = 0
try:
	while 1:
		if sequence[index] == findthis:
			return index - 1
		index = index + 1
except IndexError:
	return 0

(same for the 'for' statement.)

You could of course write a dictionary wrapper that takes numeric arguments
to the __getitem__ to be index in a sorted list of keys, and other arguments
as normal key retrieval... but you'd lose the ability to index on numbers.

> GOTCHA: (low)
>     I don't understand why we have so many C operators, such as "&" and
>     "|" and "~", but we don't have "&&" or "||" or "!"  We also have "<<"
>     and ">>".  It's bizarre that the relational and "?:" are missing.
>     Python uses so much from C to make people see what they expect to see,
>     but this is missing.  Why?

&& and || are and and or.

> GOTCHA: (low)
>     There are no loop labels, and therefore "break" and "continue" are
>     only through the next level.  This encourages the proliferation of
>     spurious boolean condition variables.  It was annoying when Pascal
>     made you do the same thing.  There is no "goto", which is how C
>     works around it.  As with many things in Python, here you force the
>     user to be tangled up with exceptions just to do very simple things.
>     That's not as clear a solution.

Only if you aren't used to exceptions. Exceptions are really very simple and
nice things. Especially back when they were just strings (before my time, but
still ;-)

> DISSIMILARITY:
>     Python uses [] to create a new empty list, which you
> 	then reference with [] subscripts.
>     Perl uses [] to create a new empty array, which you
> 	then reference with [] subscripts.
>     Python uses {} to create a new empty dictionary, which you
> 	then reference with [] subscripts.
>     Perl uses {} to create a new empty hash, which you
> 	then reference with {} subscripts.

You forget tuples, which you create with (), and subscript with [].
Subscripting is _always_ done with [], and it _always_ calls the
'__getitem__' member function (if any). There being no functional difference
is what makes it so nice :)

> DISSIMILARITY:
>     A class method call gets no class name as its implicit extra
>     argument the way an instance method would.  

that's because it doesn't know what class it's going to be called with. You
can assign it to another class on the fly :)

> DISSIMILARITY:
>     In Python, there is no difference between single and double quotes:
>     both interpolate C-style escapes like \t, and neither 
>     interpolates variables.  In Perl, single quotes do neither escapes
>     nor variables, but double quotes do both.

There are 'raw' strings though, 'r"<string>"', that dont do backslashes.

> DISSIMILARITY:
>     There are no private variables in a module or a class.
>     They can always be fully-qualified and accessed from
>     without.  Perl can do this with file-scoped lexicals,
>     but still can't do so with data members (modulo obscure
>     tricks such as using a non-hash for an object).

There is some namemangling though, for datamembers/functions that start with
a single _, for hiding/overriding purposes. (those mmebers get the classname
encoded in, so it's dependant on the class it was called on.)

> GOTCHA: (high)
>     Python has no manpages!  The horror!!!!!!!!!!!!!!!!!!!!!!
>     ENODOC

Damn, i hadn't even noticed that. Can you imagine ? I guess the '__doc__'
attributes on objects are enough manpage for me. ;)

> DISSIMILARITY:
>     Python doesn't convert between strings and numbers unless you tell
>     it to.  And if you don't tell it to, you get an exception.  Therefore
>     you have no idea what these 
> 	x = y + z
> 	x = y - z
> 	x = y * z
>     are really doing.  The first would concat strings or lists, the last would
>     repeat them.  Personally, I don't care for this, because I always
>     wonder what subtracting one string or list from another would be.

It's worse. _noone_ has any idea what you're doing until you're acutally
doing it. x, y and z can be any type of object, even a type of object that's
loaded in on demand or constructed on the fly.

> GOTCHA: (high)
>     This is a big surprise: strings are not atomic (although they are
>     immutable).  They are instead sequences of characters.  This comes
>     up in strange places.  For example:	
> 	>>> for c in ("weird", "bits"):
> 	...      print c
> 	... 
> 	weird
> 	bits
> 	>>> for c in ("weird"):
> 	...      print c
> 	... 
> 	w
> 	e
> 	i
> 	r
> 	d
>     The second case autosplit the characters!  Here's another:
> 	>>> print map(None, "stuff")
> 	['s', 't', 'u', 'f', 'f']
> 	>>> print map(None, "stuff", "here")
> 	[('s', 'h'), ('t', 'e'), ('u', 'r'), ('f', 'e'), ('f', None)]
>     (Python's map None is like Perl's map $_.) 

Wait, wait, you're doing two different things here. First off, you called
'for' with different types of arguments, the first time with a tuple of
strings, the second type with just a string. As a string is a sequence
object, it can be indexed, and the for loop wil 'iter' over the characters
in it. Perhaps you meant to do:

>>> for c in ("weird",):
...     print c
... 
weird

Or maybe

>>> for c in ("weird" + "bits"):
...     print c
... 
w
e
i
r
d
b
i
t
s

But they are definately not the same :)

As for the map(), almost the same. In the first instance you provide one
sequence, so map will pass 'None' a single argument, in the second 'None'
gets passed two items, and None returns it right back. If you want the
sequences turned into lists and concatenated, use + instead of ,

> GOTCHA: (high)
>     Because everything is a reference, and there's no way to dereference
>     that reference, it turns out that there is no trivial way to copy
>     a list!  This fails:
> 	x = [1,2]
> 	y = x
>     Because you don't get a new list there, just a copy to an
>     old one.  Suggested work-arounds include
> 	y = x[0:]
> 	y = x[:]
> 	y = x + []
> 	y = x * 1
>     This forces people to think about references, again.    
>     So much for lists being first class citizens!  Compare 
>     this with Perl's
> 	@x = (1,2);
> 	@y = @x;
>     Or even with references:
> 	$x = [1,2];
> 	$y = [ @$x ]; 
>     or 
> 	@y = @$x;

>>> import copy
>>> print copy.__doc__
Generic (shallow and deep) copying operations
=============================================
<etc>

> GOTCHA: (low)
>     You have insert and append methods for lists, but only
>     a del function.  Why is it a function not a method, and
>     why isn't it spelled out?  Apprently the fashionable wayto do this is
>     now
> 	a[2:3] = []
>     Which of course, deletes only one element.  ARG.

You can del a[3], or del a[3:5]

> 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.

Try eval(number, {}, {}). No sys or os module to call, no other variables
what so ever. Personally, i think being able to say, say, '4**5/3%2' in any
instance where the program asks you for a number is a coolness.

> 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.

Use re, perl regexps.

>     And I'd jolly well like to know why I wasn't allowed to use
> 	print "int of %f is %.0f" % (2.5) * 2
>     or if needed, 
> 	print "int of %f is %.0f" % ( (2.5) * 2 )

Try print "int of %f is %.0f" % ((2.5,) * 2 )
"Yes, the trailing comma counts" :)

> QUESTION:
>     What is and what is not thread safe?

Everything is thread safe. Or rather, there will at all times be only one
thread executing the Python interpreter.

Oh, damn, i erased the pow() thing. Well, anyway, 

>>> 2**2**2
16
>>> 4**4**4
Traceback (innermost last):
  File "<stdin>", line 1, in ?
OverflowError: integer pow()
>>> 4**4**4L
13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096L

Is that what you meant ? You missed that gotcha... no automatic conversion
between int and longint. <wink>

The worst thing about python is what it does to your programming skills. gcc
is getting tired of warning me of syntax errors due to python syntax in my C
:-)

Pyton'ly y'rs,

-- 
Thomas Wouters <thomas at xs4all.net>

Hi! I'm a .signature virus! copy me into your .signature file to help me spread!




More information about the Python-list mailing list