Re: Python Design Principles

2005-09-10 Thread Fredrik Lundh
[EMAIL PROTECTED] wrote:

 After all, the fact that Python is not strongly typed and is
 interpreted rather than compiled

if you think those are facts, you don't understand how Python
works.

(hint: Python's both strongly typed *and* compiled)

 sacrificing programmer producitivity

the ability to save a newline here and there doesn't affect the
programmer productivity in any way whatsoever.

/F 



-- 
http://mail.python.org/mailman/listinfo/python-list


Python Design Principles

2005-09-09 Thread lechequier
In a previous post, I asked about the inconsistency in usage patterns
in operating on mutable and immutable types. Thanks Dave and everyone
else for answering my question so thoughtfully and helping me to
understand the reasoning about why the different usage patterns are not
deemed to be inconsistent.

But I am still puzzled by the argument that has been given for why
methods that operate on mutable types should return None, namely, that
the designers of python didn't want the users to shoot themselves in
the foot by thinking a method simply returned a result and left the
data structure unchanged.

In the context of fundamental design principles, if you asked a random
sample of Python gurus what is more Pythonesque: preventing users from
shooting themselves in the foot or making things easier to accomplish,
my impression is that people would overwhelmingly choose the latter.
After all, the fact that Python is not strongly typed and is
interpreted rather than compiled gives plenty of ways for people to
shoot themselves in the foot but what is gained is the abilitity to do
more with less code.

But in this instance, by not allowing operations on mutable types to
return the mutated objects, it seems that the other side is being
taken, sacrificing programmer producitivity for concerns about
producing possible side effects. It is somewhat ironic, I think, that
Java, a language whose design principles clearly side on preventing
users from shooting themselves in the foot, much more so thatn Python,
generally allows you to get back the mutated object.

I'm not trying to change minds here but just to understand better how
this particular design decision fits into Python's overall design
principles.

thanks,
Scott

Dave Benjamin wrote:
 [EMAIL PROTECTED] wrote:
  Let's say I define a list of pairs as follows:
 
 l = [('d', 3), ('a', 2), ('b', 1)]
 
 
  Can anyone explain why this does not work?
 
 h = {}.update(l)
 
 
  and instead I have to go:
 
 h = {}
 h.update(l)
 
  to initialize a dictionary with the given list of pairs?
 
  when an analagous operation on strings works fine:
 
 s = .join([d,o,g])
 
 
  Seems inconsistent.

 Python is actually quite consistent in this regard: methods that modify
 an object in-place return None; methods that do not modify an object
 in-place return a new object instead. Since strings are immutable, they
 cannot be modified in-place, so it makes sense for the join method to
 return a new string. On the other hand, Python's dictionaries are
 imperative-style and so most operations on a dictionary modify an
 existing dictionary.

 I was initially bothered by the phenomenon of so many methods returning
 None because they could not be chained. But I have come to deeply
 appreciate this style for a couple of reasons. First, it makes it clear
 which methods are side-effecting (like update) and which are not (like
 sort).

 Second, it is not always clear what a good return value is for a
 mutator. Perhaps {}.update() should return the dictionary, making
 chaining convenient. Perhaps it should return the total number of items
 after updating. Or maybe it should return the number of new keys that
 were added, or a list of those keys. All of these are plausible
 behaviors; the problem is that update is not a function. Its job is to
 change something, not return something. Any possible return value would
 be a convenience for certain tasks and useless for other tasks.

 It's also hard to remember, in my opinion. For example, JavaScript has a
 push method on the Array object which behaves like Python's append
 method on lists:

 js var a = [];
 js a.push(5);
 1
 js a.push(6);
 2

 I bet you that almost nobody knows that push returns the new length of
 the Array. It could just as easily have returned a here. I could
 always write a.length, if I really needed to know the new length. This
 sort of thing becomes language trivia, and when I write in JavaScript I
 always ignore the result of push because, even if *I* know what it
 returns, chances are that my readers don't.

 Another reason that Python adopts the convention of returning None for
 mutators is that it discourages the use of side-effecting code in
 expressions. Mixing side-effects with expressions can lead to code that
 is hard to read and understand. This is often debated by those who know
 better and wish to write things like h.update(a).update(b) (method
 chaining) or while (line = file.readline()):  Python's decision is
 pretty clear, and it's also evident in the division between statements
 and expressions.

 Regardless of whether you like Python's style decision or not, if you
 dig deeper I think you will find that it is pretty consistent, and that
 there are useful benefits to Python's way of handling side effects.

 Dave

 PS. If mutators had to return a value, I'd have them return self,
 probably 95% of the time. But then, it wouldn't be Python anymore. It'd
 be Ruby, maybe.

-- 

Re: Python Design Principles

2005-09-09 Thread Neal Norwitz
[EMAIL PROTECTED] wrote:

 But I am still puzzled by the argument that has been given for why
 methods that operate on mutable types should return None, namely, that
 the designers of python didn't want the users to shoot themselves in
 the foot by thinking a method simply returned a result and left the
 data structure unchanged.

Let me try to answer your question with a question.  Given this code:

   d = {}
   e = d.update([(1, 2)])

If .update() returned a dictionary, does d == e?

I'm not sure what you would guess. I am pretty sure that everyone
wouldn't agree whether d should equal e or not.  If they are not equal,
that would mean a new copy would be made on each update which could be
incredibly expensive in speed and memory.  It is also different from
how Python works today, since the update() method mutates the
dictionary.

 In the context of fundamental design principles, if you asked a random
 sample of Python gurus what is more Pythonesque: preventing users from
 shooting themselves in the foot or making things easier to accomplish,
 my impression is that people would overwhelmingly choose the latter.

Probably true, but ...

 After all, the fact that Python is not strongly typed and is
 interpreted rather than compiled gives plenty of ways for people to
 shoot themselves in the foot but what is gained is the abilitity to do
 more with less code.

I think most people programming Python are pretty pragmatic.  There is
no single language that is ideal in all circumstances.  There are
necessarily some trade-offs.  Many believe that tools can help bridge
this gap.  There are at least 2 tools for finding bugs (or gotchas) of
this sort:  pychecker and pylint.

 But in this instance, by not allowing operations on mutable types to
 return the mutated objects, it seems that the other side is being
 taken, sacrificing programmer producitivity for concerns about
 producing possible side effects. It is somewhat ironic, I think, that
 Java, a language whose design principles clearly side on preventing
 users from shooting themselves in the foot, much more so thatn Python,
 generally allows you to get back the mutated object.

I think Python has attempted to create an internal consistency.  I
believe Java has tried to do the same.  However, these aren't the same
sets of consistency.  People are always going to have assumptions.
Python strives to be as intuitive as possible.  However, it can't be
right 100% of the time for all people.

HTH,
n

-- 
http://mail.python.org/mailman/listinfo/python-list