Do any of you recommend Python as a first programming language?

P

Paul Rubin

John Nagle said:
What a mess. That's some professor inventing his very own variation on
predicate calculus and writing a book using his own notation and terminology.

I thought it was all pretty standard. It's the same notation I see in
other PL stuff.
There's no sign of footnotes or references to prior work.

Maybe he'll add that. It's a work in progress.
Back when I was doing program verification work, we used to refer to
stuff like that as the "logic of the month club".

I thought the book was pretty good and I've learned quite a bit from
the parts I've read. Also, the author is one of the big cheeses in
the SML world, if that matters.
 
J

John Nagle

Paul said:

What a mess. That's some professor inventing his very own variation on
predicate calculus and writing a book using his own notation and terminology.
There's no sign of footnotes or references to prior work. The notation
doesn't seem to do anything not previously possible; it's just different.

Back when I was doing program verification work, we used to refer to
stuff like that as the "logic of the month club".

John Nagle
 
S

Steven D'Aprano

That's some professor inventing his very own variation on predicate
calculus and writing a book using his own notation and terminology.
There's no sign of footnotes or references to prior work. The notation
doesn't seem to do anything not previously possible; it's just
different.

You say that as if it were unusual in maths circles :)
 
B

Berco Beute

For students 9th - 12th grade, with at least Algebra I. Do you think
Python is a good first programming language for someone with zero
programming experience? Using Linux and Python for first exposure to
programming languages and principles.

Thank you.

Yes. The nice thing with Python is that you can start off with really
simple examples and slowly build up the complexity along with the
understanding of the students. There's no need to explain OO before
the students can write their first 'Hello, world'.

There's almost no limit to how 'shallow/deep' you can go with Python.

2B
 
A

Arnaud Delobelle

You say that as if it were unusual in maths circles :)

Haha. As opposed to programmers who have all agreed to use the same
language.

Anyway, I have browsed the book and agree with Paul Rubin that there
doesn't seem to be any unusual notation in it, although there are a
numbers of topics that I am not really familiar with.
 
B

Ben C

Absolutely. I love using Python in "the real world" but it is
fantastic for beginning programmers.

Python enforces good habits and presents many opportunities to discuss
programming from an academic perspective. Why does Python not have a
switch or until statement?

Why doesn't it?
Why are very common objects (stack, queue,
linked list) not builtin? etc.

I think I know this one: you just use builtin lists to do stacks, queues
and, er, lists.
 
M

Martin P. Hellwig

jmDesktop said:
For students 9th - 12th grade, with at least Algebra I. Do you think
Python is a good first programming language for someone with zero
programming experience? Using Linux and Python for first exposure to
programming languages and principles.

Thank you.

I for one can't really answer this question but I wanted to share the
reason for that :) since I worked in the dutch high school equivalent
for a number of years.

First and most important is I think the objective you want to reach, at
my school we had a number of angles:
- A math teacher using it as a simpler way of writing examples and
explanation while being able to let the students see what is going on
and why.
- A basic grade computer introduction, to let them feel what automation
is about, more like the philosophy of it.
- A higher grade computer science (well for high school that is)
introduction in to programming.
- A explanation what makes the computer tick and how it does it (cpu
architecture, memory management etc.)

In my opinion python is extremely useful for all of these objectives,
except for the last one, this would be more a job for assembler. My
school decided not to go in depth to that because we felt it would be
out of reach for the majority of the students and we didn't wanted to
spoil the students when they decide to take up CS in university later on.
 
D

Dustan

For students 9th - 12th grade, with at least Algebra I. Do you think
Python is a good first programming language for someone with zero
programming experience? Using Linux and Python for first exposure to
programming languages and principles.
Yes.

Thank you.

You're welcome.
 
A

Aahz

Also, despite reassurances to the contrary, I still get the impression
that there is a strong anti-lambda sentiment among the Python "in"
crowd. Is it just a question of the word "lambda," as opposed to
perceived cleaner syntax?

The problem with lambda is that too often it results in clutter (this is
a strictly made-up example off the top of my head for illustrative
purposes rather than any real code, but I've seen plenty of code similar
at various times):

gui.create_window(origin=(123,456), background=gui.WHITE,
foreground=gui.BLACK, callback=lambda x: x*2)

That means I need to pause reading the create_window() arguments while I
figure out what the lambda means -- and often the lambda is more
complicated than that. Moreover, because the lambda is unnamed, it's
missing a reading cue for its purpose.
 
G

George Sakkis

The problem with lambda is that too often it results in clutter (this is
a strictly made-up example off the top of my head for illustrative
purposes rather than any real code, but I've seen plenty of code similar
at various times):

gui.create_window(origin=(123,456), background=gui.WHITE,
foreground=gui.BLACK, callback=lambda x: x*2)

That means I need to pause reading the create_window() arguments while I
figure out what the lambda means -- and often the lambda is more
complicated than that. Moreover, because the lambda is unnamed, it's
missing a reading cue for its purpose.

In a sense the lambda here is not unnamed; it's name is the name of
the keyword argument, 'callback', which is indeed a poor name at in
terms of self-documentation. I don't see how replacing the lambda with
a (better) named function would be any better than using the same name
as a keyword parameter.

George
 
S

Steven D'Aprano

The problem with lambda is that too often it results in clutter (this is
a strictly made-up example off the top of my head for illustrative
purposes rather than any real code, but I've seen plenty of code similar
at various times):

gui.create_window(origin=(123,456), background=gui.WHITE,
foreground=gui.BLACK, callback=lambda x: x*2)

That means I need to pause reading the create_window() arguments while I
figure out what the lambda means -- and often the lambda is more
complicated than that. Moreover, because the lambda is unnamed, it's
missing a reading cue for its purpose.


And of course this would be so much better:

def double(x): return x*2

gui.create_window(origin=(123,456), background=gui.WHITE,
foreground=gui.BLACK, callback=double)


Not.

The source of the "clutter" (having *less* code is clutter???) and
confusion isn't the lambda, it's the callback.
 
R

Roy Smith

Also, despite reassurances to the contrary, I still get the impression
that there is a strong anti-lambda sentiment among the Python "in"
crowd. Is it just a question of the word "lambda," as opposed to
perceived cleaner syntax?

There is a fundamental disharmony in how functions and other objects are
treated in Python. If I say:

x = ['surprise', 'fear', 'ruthless efficiency']

I've done two things. First, I've created a list, then I've bound the name
x to that list (maybe "bound" is not exactly the right terminology). Until
the assignment happend, the list had no name. In fact, it still has no
name; there's just a reference to it stored in a variable whose name is x.
If I were to then do

y = x

now y and x have equal relationships to the original list. The list's name
is no more x than it is y, since the whole concept of "the name of the
list" doesn't have any meaning in Python.

On the other hand, when I do:

def torture():
woman.putInChair()
cushion.poke()
rack.turn()

I've also done two things. First, I've created a function object (i.e. a
lambda body), and I've also bound the name torture to that function object,
in much the same way I did with the list. But, it's different. The
function object KNOWS that it's name is torture. When I later reassign it
to another name and run it:

weapon = torture
weapon()

This is what I get:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in torture
NameError: global name 'woman' is not defined

Notice, the second line in the stack trace identified the function's name
as "torture", not "weapon". Because that IS the function's name. Lists
are anonymous. Functions have names (as do a few other things like classes
and modules). If I ask a list what its name is, I get:

AttributeError: 'list' object has no attribute '__name__'

but, if I ask a function what it's name is (regardless of what name I've
bound it to), I get the right answer:

If we created lisp-like lambdas and bound them to names like we did with
other types of objects, we wouldn't have that.

What Python give us with lambdas is some half-way thing. It's not a full
function, so it's something that people use rarely, which means most people
(like me) can't remember the exact syntax. Even when I know it's the right
thing to be using in a situation, I tend not to use it simply because the
path of least resistance is to write a one-off function vs. looking up the
exact syntax for a lambda in the manual.
 
F

Fuzzyman

The problem with lambda is that too often it results in clutter (this is
a strictly made-up example off the top of my head for illustrative
purposes rather than any real code, but I've seen plenty of code similar
at various times):

gui.create_window(origin=(123,456), background=gui.WHITE,
foreground=gui.BLACK, callback=lambda x: x*2)

That means I need to pause reading the create_window() arguments while I
figure out what the lambda means -- and often the lambda is more
complicated than that. Moreover, because the lambda is unnamed, it's
missing a reading cue for its purpose.


I find lambdas invaluable very frequently - often to avoid the reading
clutter.

* Transforming function calls

something.Event += lambda sender, event: real_handler()

* Properties

name = property(lambda self: self.__name, __set_name)

* Very short functions where extra lines reduce readability

if direction == 'left':
transform = lambda x, y: -x
else:
transform = lambda x, y: x

* Functions that take functions as arguments

old_list = [(3,1), (2, 2), (1, 3)]
new_list = sorted(old_list, key=lambda x: x[1])

new_data = process(data_Set, lambda x: x+1)
new_data2 = process(data_Set, lambda x: x-1)


I don't think any of these are unreadable or improved by defining a
'real' function.

Michael
http://www.ironpythoninaction.com
 
F

Fuzzyman

Linux and Python are a nearly ideal combination for this. Be aware that
at some point, you will likely have to dig into C, the primary language
used to implement both Linux and Python.

I've been using Python for five years and now work full-time as a
Python programmer. I've not had to hit C. :)

Michael Foord
http://www.ironpythoninaction.com
 
T

Terry Reedy

| There is a fundamental disharmony in how functions and other objects are
| treated in Python.
[snip]

For scalars and collections, print object prints the value, which is the
main part of the object, in a form close to (or equal to) how it is created
in code.

For functions, classes, and modules, this would be awkward to impossible
since the corresponding code is not part of the object and may be either
bulky and slow to access, not accessible, or non-existent. So these three
get name attitributes as a substitute. Function names are also used to
improve tracebacks over 'function at line nnn'.

Perhaps for these types, print could (should?) instead print the first list
of the doc string, if there is one.

Method objects inherit the name of the function they wrap. Other internal
types are left anonymous, but how could they get a name when there is no
code to give them a name.

Yes, fundamentally different categories of types are (sensibly) treated
differently with repect to definition and namespace names, but calling that
'disharmony' depends on the listener.

| If we created lisp-like lambdas and bound them to names like we did with
| other types of objects, we wouldn't have that.

Correct. Tracebacks would always instead of just occasionally be less
useful as functions would always be identified only by file and line
number, as today with lambda expression.

Terry Jan Reedy
 
S

Steven D'Aprano

On the other hand, when I do:

def torture():
woman.putInChair()
cushion.poke()
rack.turn()

I've also done two things. First, I've created a function object (i.e.
a lambda body), and I've also bound the name torture to that function
object, in much the same way I did with the list. But, it's different.
The function object KNOWS that it's name is torture.

No it does not. Function objects don't know their name. All they know is
that they have a label attached to them that is useful to use as a name
in some contexts, e.g. when printing tracebacks. It's just a label,
nothing more.

You can prove that for yourself with a few simple tests. Firstly, we can
prove that functions don't know what they are called by writing a
recursive function:


def spam(n):
if n <= 1: return "Spam"
return "Spam " + spam(n-1)


If spam() knows what it is called, then you should be able to rename the
function and the recursive call will continue to work. But in fact,
that's not what happens:

'Spam Spam Spam'


But now watch what happens when we create a new function with the name
spam. It hijacks the recursive call:

.... return "ham-like meat product"
....'Spam ham-like meat product'

The function formerly known as "spam" isn't calling itself, it is merely
calling a function by name "spam". But we can see that the function
tasty_stuff() is still using the old "spam" label for itself:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in spam
TypeError: unsupported operand type(s) for -: 'str' and 'int'


Unfortunately there's nothing we can do to fix that error. Even though
the function object has an attribute "__name__" (also known as
"func_name") which is set to spam, it isn't used for tracebacks. Instead,
the label comes from a read-only attribute buried deep in the function
object:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: readonly attribute


This is a mistake, in my opinion. It's an arbitrary decision to make this
read-only (as far as I can tell), which goes against the grain of
Python's "we're all consenting adults here" philosophy.

By the way, in case you're thinking that wanting to change the (so-
called) name of a function is a silly think to do, not at all. Consider
factory functions:

def factory(how_much):
def f(n=1):
for i in range(n):
print "I love spam a %s" % how_much
return f

Every function created by the factory has the same "name", no matter what
name you actually use to refer to it. factory('little') and
factory('lot') both uselessly identify themselves as "f" in tracebacks.

The truth is that objects don't know what name they have, because objects
don't have names. The relationship is the other way around: names have
objects, not vice versa. Some objects (functions, classes, anything
else?) usefully need a label so that they can refer to themselves in
tracebacks and similar, and we call that label "the name", but it's just
a label. It doesn't mean anything.


[snip]
What Python give us with lambdas is some half-way thing. It's not a
full function, so it's something that people use rarely,

Which people?
which means most people (like me) can't remember the exact syntax.

Speak for yourself, not for "most people".

Even when I know
it's the right thing to be using in a situation, I tend not to use it
simply because the path of least resistance is to write a one-off
function vs. looking up the exact syntax for a lambda in the manual.

lambda arguments : expression

Why is that harder to remember than this?

def name ( arguments ) :
block

And don't forget to include a return statement, or you'll be surprised by
the result of the function.
 
K

Kay Schluehr

Haha. As opposed to programmers who have all agreed to use the same
language.

Anyway, I have browsed the book and agree with Paul Rubin that there
doesn't seem to be any unusual notation in it, although there are a
numbers of topics that I am not really familiar with.

The author at least introduces his notation in the initial chapter.
This is good style among mathematicians who introduce conventions at
the beginning of their books or in an appendix.

Note that I'm with Paul here but I'm not sure what John is complaining
about anyway. Maybe sequent calculus ( natural deduction ) which was
introduced by Gentzen around 75 years ago?

http://en.wikipedia.org/wiki/Sequent_calculus
 
R

Roy Smith

Steven D'Aprano said:
No it does not. Function objects don't know their name. All they know is
that they have a label attached to them that is useful to use as a name
in some contexts, e.g. when printing tracebacks. It's just a label,
nothing more.

I think we're arguing the same thing. When you write

def foo():
whatever

you create an object which contains the string "foo", retrievable through
its __name__ attribute. That's what I meant by "it knows its name"
Which people?


Speak for yourself, not for "most people".

Well, OK. When I said, "most people", I really meant "I know about me, and
I'm guessing about other people". I still think it's a fair statement that
if you look any large collection of Python code, you will find many more
uses of def than of lambda.
lambda arguments : expression

Why is that harder to remember than this?

def name ( arguments ) :
block

because I remember things I use often, better than I remember things I use
infrequently.
 
S

Steven D'Aprano

I think we're arguing the same thing. When you write

def foo():
whatever

you create an object which contains the string "foo", retrievable
through its __name__ attribute. That's what I meant by "it knows its
name"


But that's not true. Firstly, you can't access the __name__ attribute
unless you already have a reference to the object (not necessarily a
name), so clearly the __name__ attribute isn't how you retrieve objects.

Secondly, the __name__ attribute has no special purpose. It's not even
used for tracebacks.

.... return "result"
....Traceback (most recent call last):
Traceback (most recent call last):
'something'
 
T

Terry Reedy

| Unfortunately there's nothing we can do to fix that error. Even though
| the function object has an attribute "__name__" (also known as
| "func_name") which is set to spam, it isn't used for tracebacks. Instead,
| the label comes from a read-only attribute buried deep in the function
| object:
|
| >>> tasty_stuff.func_code.co_name = 'yummy meat-like product in a can'
| Traceback (most recent call last):
| File "<stdin>", line 1, in <module>
| TypeError: readonly attribute

The fact that .func_name (which is writeable) is not used at first
surprised me until I remembered that code objects can potentially be used
by multiple function objects and hence are not connected to any one in
particular.

| This is a mistake, in my opinion. It's an arbitrary decision to make this
| read-only (as far as I can tell), which goes against the grain of
| Python's "we're all consenting adults here" philosophy.
|
| By the way, in case you're thinking that wanting to change the (so-
| called) name of a function is a silly think to do, not at all. Consider
| factory functions:
|
| def factory(how_much):
| def f(n=1):
| for i in range(n):
| print "I love spam a %s" % how_much
| return f
|
| Every function created by the factory has the same "name", no matter what
| name you actually use to refer to it. factory('little') and
| factory('lot') both uselessly identify themselves as "f" in tracebacks.

workaround:<function ftest at 0x00C01070>

so:
def factory(how_much):
'param how_much MUST be a legal name'
exec '''def %(how_much)s(n=1):
for i in range(n):
print "I love spam a %(how_much)s"''' % {'how_much': how_much}
return locals()[how_much]

f2=factory('much')
print f2.func_name

prints 'much'
But certainly setting .co_name directly would be easier

Terry Jan Reedy
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top