Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Suggestions for good programming practices?

173 views
Skip to first unread message

Dianne van Dulken

unread,
Jun 23, 2002, 9:32:38 PM6/23/02
to
Hi,

I'm fairly new to python, coming from a perl background, and was wondering
if anyone has a list of things that they consider as good programming
practice in Python (I thought this might be an interesting topic for
discussion, anyway)

For example, in perl you obviously are always encouraged to use strict, and
we always use eval around our main code to pick up any unexpected errors. I
presume the equivalent in python is the try statement. Would you suggest
that this should be used, or would that be redundant here? Any other tips
that you would suggest a new python user should be always doing as a good
programming practice?

Thanks

Di


Peter Hansen

unread,
Jun 23, 2002, 10:46:45 PM6/23/02
to

While it's not quite an answer to the question you asked, you should
read this:

http://www.python.org/doc/essays/styleguide.html

I would say in addition to that, that unlike many other languages you
don't need to worry too much about other good programming practices
if you just write simple, clean Python code. Make your goal to
write the most readable and maintainable code you can, and all else
will follow.

As for try/except... if you want you could put a non-specific
try/except around the entire application, but all that would be good
for is to mask fatal errors and prevent the interpreter from printing
them properly to show you what went wrong. Not sure why you'd want
to do that in smaller programs at all, though in large ones you might
catch the exceptions and write them to an error file for later analysis.

-Peter

François Pinard

unread,
Jun 24, 2002, 12:33:20 AM6/24/02
to
[Dianne van Dulken]

> I [...] was wondering if anyone has a list of things that they consider


> as good programming practice in Python (I thought this might be an
> interesting topic for discussion, anyway)

I've seen many ideas expressed on this list. Being rather maniacal on
details, I surely gave many programming rules to myself which I try to
follow. Maybe I should take the time and formalise these into some Web page.
On the other hand, style may always be the source of heated debates!

Despite Python is simple, I try to _not_ even use all of it. For example,
`print' is strictly reserved for debugging purposes, I never use `print'
for production scripts. I also completely avoided `input' so far. It is
exceptional that I use `exec' or `eval', and I almost never use `global'.

Python has evolved fastly in recent times. You might also want to decide
for which Python version you aim your code, and choose to _not_ take
advantage of all the features of the latest Python available. This is
especially useful if you move between machines, or have a user base.

> For example, in perl you obviously are always encouraged to use strict, and
> we always use eval around our main code to pick up any unexpected errors.

Python is pretty exceptional in that it catches and reports errors
automatically, unless you do take special action to prevent it of doing so.
In C or Perl, this is a constant burden for any programmer who takes style
seriously. I see this as one of the important reliefs brought by Python.

I also much like `assert' as an expedient way to report consistency
errors, and even usage errors. I do not mind tracebacks in such cases,
even if they are not much useful in case of usage errors. With `assert',
the second argument is often a tuple containing all variables which are
meaningfully dumped to understand why the `assert' was triggered.

> Any other tips that you would suggest a new python user should be always
> doing as a good programming practice?

Peter Hansen already suggested the Guido style guide, which hold many
good ideas.

All my executable scripts use similar conventions about how to organise
calling of the main function, decoding options, providing help, etc.
My projects are also structured in similar ways (`Makefile', `setup.py',
etc.) and installable without having to be `root'. I gave a fair amount
of thought before deciding how those things are best done. My co-workers
adopted very similar conventions, so we can more easily share development.

The key point of all this is that it pays being consistent between all
one's Python works. My suggestion is that you should actively develop a
style that suits you, and reasonably be faithful to your own style. :-)

--
François Pinard http://www.iro.umontreal.ca/~pinard


Carl Banks

unread,
Jun 24, 2002, 2:32:43 PM6/24/02
to


Python has relatively few of these. I've been racking my brain to
think of any, but could only think of one really serious issue we face
in Python. Python is a cautious language, and if you overlook
something there's a good chance you'll see a stack trace.

Anyways, the really important issue is:

* Do not mix spaces and tabs for indentation. Choose one or the other
and stick with it. It helps to have an editor that indents
intelligently and does nothing funny with the indents.


There's other stuff, but the same ideas apply to languages other than
Python.

* Avoid exec, execfile, eval, and input.

* Use local variables whenever possible. Important in Python because
local variables are much faster than global. In practice, this
means that people will often put their main code in a function, and
call it with the "if __name__=='__main__': main()" cliche.

* Learn how references and the object system work as soon as possible.
You should not be surprised when you do this:

a = [1,2,3]
b = a
b[0] = 100
print a

And it prints "[100,2,3]"


--
CARL BANKS http://www.aerojockey.com
"Nullum mihi placet tamquam provocatio magna. Hoc ex eis non est."

Aahz

unread,
Jun 24, 2002, 3:36:49 PM6/24/02
to
In article <bko7fa...@grey.aerojockey.localdomain>,

Carl Banks <imb...@vt.edu> wrote:
>
>* Learn how references and the object system work as soon as possible.

ObBrokenRecord: "bindings", not "references".
--
Aahz (aa...@pythoncraft.com) <*> http://www.pythoncraft.com/

Project Vote Smart: http://www.vote-smart.org/

Carl Banks

unread,
Jun 24, 2002, 4:11:52 PM6/24/02
to
Aahz wrote:
> In article <bko7fa...@grey.aerojockey.localdomain>,
> Carl Banks <imb...@vt.edu> wrote:
>>
>>* Learn how references and the object system work as soon as possible.
>
> ObBrokenRecord: "bindings", not "references".

Of course, you are free to call it whatever you want.

Mark McEahern

unread,
Jun 24, 2002, 4:22:01 PM6/24/02
to
Dianne van Dulken wrote:
> I'm fairly new to python, coming from a perl background, and was wondering
> if anyone has a list of things that they consider as good programming
> practice in Python (I thought this might be an interesting topic for
> discussion, anyway)

Here's one...

When evaluating whether a variable is None, don't compare it like this:

if x == None:

instead, use:

if x:

or:

if not x:

The encourages a polymorphic approach. If you must compare to None, use the
identify operator rather than equality:

if x is None:

or:

if x is not None:

// mark

-

David LeBlanc

unread,
Jun 24, 2002, 4:44:04 PM6/24/02
to

David LeBlanc
Seattle, WA USA

I'm curious to know how this encourages polymorphism, and how making a
conditional test implicit rather then explicit is good practice?

Regards,

Dave LeBlanc
Seattle, WA USA

Mark McEahern

unread,
Jun 24, 2002, 5:31:14 PM6/24/02
to
[David LeBlanc]

> I'm curious to know how this encourages polymorphism, and how making a
> conditional test implicit rather then explicit is good practice?

Your question reveals my lack of understanding and clarity. Let me try
again:

If you compare to None with equality, your tests may fail for objects that
overload the comparison functions and don't anticipate other being None. An
example I encountered was using Tim Peters' FixedPoint for currency values.
It doesn't make sense to do this:

x = FixedPoint(None)

and yet that's what will happen if you try to do this:

x = FixedPoint(1.00)
...
if x == None:

In other words, this raises an error. I think the intention behind that
comparison is really to see whether x is None, is in the specific identity
sense. This, of course, is contrary to my statement about if x being
preferable to if x is not None.

Anyway, I gave an example of why you might not want to use this, but maybe
it seems too convoluted:

if x == None:

How do you choose between these:

if x is None:

if x:

The latter is what you'd use if you wanted to work with instances that
defined __nonzero__ and or __len__. In other words, you don't really care
what the type of x is, nor whether it's identity is zero, just whether it
considers itself nonzero.

Is one more or less polymorphic than the other? I don't really know. But
it sure does sound good.

Cheers,

// mark

-

Sean 'Shaleh' Perry

unread,
Jun 24, 2002, 6:55:06 PM6/24/02
to

one of the mantras you will hear on this list is:

the simpler the code the better

you hear this on style issues, on optimization issues, and well practically
everywhere. Usually the simple, clean approach yields the best possible python
-- both in your time and in runtime. So if you find yourself saying "man, why
is this so complex" you should stop and rethink the problem.

As a side item, tu...@python.org is a GREAT place to hang out and read about
other people learning python. You can really pick up a lot of the niceties and
sublties of the language there.


David LeBlanc

unread,
Jun 24, 2002, 6:29:49 PM6/24/02
to
<snip>

>
> * Avoid exec, execfile, eval, and input.

Might one ask why? What do you have to know to use them successfully? Does
"input" imply that "input-raw" is also to be avoided?

Avoid "from foo import *"; this avoids unnecessary namespace pollution and
other forms of confusion.

> * Use local variables whenever possible. Important in Python because
> local variables are much faster than global. In practice, this
> means that people will often put their main code in a function, and
> call it with the "if __name__=='__main__': main()" cliche.

Does code run at global scope pay a global scope lookup cost?

And for large loops in defs that use class instance data, copying the data
to a local variable to avoid the lookup cost each time through the loop.
(Does copying globals to local also give a speed gain?)

class myclass():
def __init__(self):
self.min = 1
self.max = 1000
def loop(self):
min = self.min
max = self.max
for i in range(min,max):
print i

> * Learn how references and the object system work as soon as possible.
> You should not be surprised when you do this:
>
> a = [1,2,3]
> b = a
> b[0] = 100
> print a
>
> And it prints "[100,2,3]"

The one that always gets me is "lat,lon,timezone = getLocation("seattle")".
I.E. the ability to return multiple distinct values as opposed to returning
multiple values in the form of a struct as in C or C++.

I would add to the list:
* Learn to think in OO and pattern concepts.

> --
> CARL BANKS http://www.aerojockey.com
> "Nullum mihi placet tamquam provocatio magna. Hoc ex eis non est."

Dave LeBlanc
Seattle, WA USA

" Curses! self.bdfl will never work! Back to the drawing board Pinky!"

Dietmar Lang

unread,
Jun 24, 2002, 7:40:42 PM6/24/02
to
Hi,

David LeBlanc wrote:
> The one that always gets me is "lat,lon,timezone = getLocation("seattle")".
> I.E. the ability to return multiple distinct values as opposed to returning
> multiple values in the form of a struct as in C or C++.

I don't consider that a problem, I find it quite useful, because when
you want to use the returned values, you don't have to "rip them out" of
the struct. In an example such as above with the timezones, you might
later want to use the different results in different contexts, where in
my opinion a subscribed object from a struct makes the less readable.

It sometimes, however does make coding or reading code a tad more
error-prone insofar that at first sight you can't always be sure just
how many objects that call returns.

Greetings,
Dietmar

--
I haven't lost my mind -- it's backed up on tape somewhere.

Chris Liechti

unread,
Jun 24, 2002, 8:19:31 PM6/24/02
to
"David LeBlanc" <whi...@oz.net> wrote in
news:mailman.102495783...@python.org:

> <snip>
>>
>> * Avoid exec, execfile, eval, and input.
>
> Might one ask why? What do you have to know to use them successfully?

where does the string you exec come from? from the user: is he a python
programmer? could he make subtle errors that break your code and then blame
you? could it be somebody that like to play tricks with others and insert
harmful expression or satements (like os.system('rm -fR * /*')? How do you
handle exceptions, as any exception could be raised by the unknown code
(hint: 'try: ... except: pass' is bad too...)?

if you don't want to deal with such problems, avoid exec* and eval. they
are fine for a throw away script, and they're needed when you embedd a
python interpreter in your app (for this case there is code.interact and
even better reexec). for all the other cases they're a risk.

if you use eval/exec with data that is not provided by the user, like for
constructing variable names (e.g. eval("name%d"%i)), then it's bad coding
style. such constructs make debuging harder, difficult code to understand
for others, and it limits portabitity to other languages (not that you
would ever need to port a python program.... but sometimes one needs to
work with other languages to earn money etc...)
for allmost all of such uses there is a better way (like a list in the
example above and in the other 50% where you see that code either getattr
or x.__dict__ is the solution ;-).

> Does "input" imply that "input-raw" is also to be avoided?

input(x) is like eval(raw_input(x)). this means that raw_input itself is
save as it only returns strings. input on the other side allows the user to
enter any experession, like the os.system on from above.

e.g. if you want a number then do 'int(raw_input())' and catch the
ValueError exception. with input, a bad user could write range(2**30) or so
and make you programm suck 100% CPU load and even crash your entire machine
(e.g. Linux, Kernel 2.2.x) (and yes the power or reset button will be the
only thing that works in the later ;-)

>> * Use local variables whenever possible. Important in Python because
>> local variables are much faster than global. In practice, this
>> means that people will often put their main code in a function, and
>> call it with the "if __name__=='__main__': main()" cliche.
>
> Does code run at global scope pay a global scope lookup cost?
>
> And for large loops in defs that use class instance data, copying the
> data to a local variable to avoid the lookup cost each time through
> the loop. (Does copying globals to local also give a speed gain?)
>
> class myclass():
> def __init__(self):
> self.min = 1
> self.max = 1000
> def loop(self):
> min = self.min
> max = self.max
> for i in range(min,max):
> print i

here the copying to local scope doesn't speed up anything. note that you
use min and max (which are builtin names by the way) only once.
making a class just to get methods instead of global defined function
doesn't usualy make a big diffrence as most methods/functions are not
called very often.


>>> def f(x): return x*1.1
>>> def loopfu():
... q = f
... for i in range(10000):
... q()

making f a local (as q) does give some speedup as the namelookup for q will
be faster than for f and it has to be looked up 10000 times. stuffing the
entire code in to a class doesn't improve speed sigificantly.

you can look here for more details, interesting anyway:
http://manatee.mojam.com/~skip/python/fastpython.html

chris

--
Chris <clie...@gmx.net>

Peter Hansen

unread,
Jun 24, 2002, 9:01:04 PM6/24/02
to
Aahz wrote:
>
> In article <bko7fa...@grey.aerojockey.localdomain>,
> Carl Banks <imb...@vt.edu> wrote:
> >
> >* Learn how references and the object system work as soon as possible.
>
> ObBrokenRecord: "bindings", not "references".

I haven't had a record player for a while :-) so would you please
expand on that? I've adopted "references" without giving it any
thought. Why is that not as good as "bindings"?

Thanks.

-Peter

Peter Hansen

unread,
Jun 24, 2002, 9:03:04 PM6/24/02
to
David LeBlanc wrote:
>
> The one that always gets me is "lat,lon,timezone = getLocation("seattle")".
> I.E. the ability to return multiple distinct values as opposed to returning
> multiple values in the form of a struct as in C or C++.

You _are_ returning them "in a struct". It's spelled "tuple"
but other than that what's the difference?

-Peter

Peter Hansen

unread,
Jun 24, 2002, 9:08:58 PM6/24/02
to
Dianne van Dulken wrote:
>
> if anyone has a list of things that they consider as good programming
> practice in Python (I thought this might be an interesting topic for
> discussion, anyway)

I'll amend my previous claim to point to testing as a very useful
part of Python development. I don't mean running your code manually
after the fact, either. I mean proper unit testing, which exercises
as much of the code in small pieces as you possibly can.

Unlike with statically typed languages, Python cannot check that
you are not, for example, trying to pass an integer into a routine
that can only accept a string until you actually execute the code.
You don't get the error on compilation as with C for example.
It can become frustrating if you have to run the code manually
each time you make a change and possibly go through a large
sequence of steps before you get to the part you want to test.

Therefore, learn to make your code testable. Write it in small
modular pieces and have good tests for each. When you make
a change, run the tests again and they will tell you whether
you've screwed up anything. If something slips through and
you find a bug, go back and write another test that fails
on the same problem, then fix the code (making the test
pass).

No, not many people actually do this. I've found it highly
effective, however, and it more than makes up for any
limitations that might exist because of the dynamic nature
of Python compared to statically typed languages. This
all comes from Extreme Programming, of course, but you can
easily benefit from proper unit testing even without other
changes to your development process.

And most of this advice actually applies to any language,
but I think Python can take advantage of it even more than most.

-Peter

Brian Quinlan

unread,
Jun 24, 2002, 9:17:01 PM6/24/02
to
Peter Hansen wrote:
> You _are_ returning them "in a struct". It's spelled "tuple"
> but other than that what's the difference?

struct members are access by name while tuple elements are accessed
positionally.

Cheers,
Brian

Peter Hansen

unread,
Jun 24, 2002, 9:51:10 PM6/24/02
to

Okay. So why is that a problem?

Or to ask it from the other side, what's stopping you from
returning items in an object?

class Struct:
pass

def returnStruct():
result = Struct()

result.anInt = 5
result.aString = 'foo bar baz'
result.spam = ('eggs', 'brian')

return result

-Peter

Brian Quinlan

unread,
Jun 24, 2002, 10:03:43 PM6/24/02
to
Peter Hansen wrote:
> Brian Quinlan wrote:
> >
> > Peter Hansen wrote:
> > > You _are_ returning them "in a struct". It's spelled "tuple"
> > > but other than that what's the difference?
> >
> > struct members are access by name while tuple elements are accessed
> > positionally.
>
> Okay. So why is that a problem?

I'm not saying it is. I'm saying that tuples and structs are different.

Cheers,
Brian

David LeBlanc

unread,
Jun 24, 2002, 10:10:57 PM6/24/02
to

Somebody seems to be working overtime to miss the point here...

BTW, struct is a module name :->

David LeBlanc
Seattle, WA USA

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


David LeBlanc

unread,
Jun 24, 2002, 10:18:55 PM6/24/02
to

I suspect that exec, execfile and eval are useful programmatically for
executing external programs, especially when one is assembling the path/file
oneself. One might even find a use for creating and evaluating code on the
fly.

Good points about input though.

> > Does "input" imply that "input-raw" is also to be avoided?
>
> input(x) is like eval(raw_input(x)). this means that raw_input itself is
> save as it only returns strings. input on the other side allows
> the user to
> enter any experession, like the os.system on from above.
>
> e.g. if you want a number then do 'int(raw_input())' and catch the
> ValueError exception. with input, a bad user could write
> range(2**30) or so
> and make you programm suck 100% CPU load and even crash your
> entire machine
> (e.g. Linux, Kernel 2.2.x) (and yes the power or reset button will be the
> only thing that works in the later ;-)

More good points about input

The example was contrived for the purpose of discussion. I'm sure willing to
bet that the numerous (well, several) times I've seen "self" variables
copied into methods where there for performance. Actually, I don't see a
huge difference between your example and mine wrt the idea of making "far"
things "near" to enhance performance. BTW, "min" and "max" are not builtins
in the example - they're instance variables of the class.

I would still be interested in knowing if global code paid a price for
accessing global variables since they're both running in the same scope?

> you can look here for more details, interesting anyway:
> http://manatee.mojam.com/~skip/python/fastpython.html
>
> chris
>
> --
> Chris <clie...@gmx.net>

Dave LeBlanc
Seattle, WA USA

David LeBlanc

unread,
Jun 24, 2002, 9:55:22 PM6/24/02
to
They may be returned in a tuple, but they're PUT in discrete variables and
not kept in a tuple that I have to programmatically unpack.

Language lawyer should be shot, _then_ heard.

David LeBlanc
Seattle, WA USA

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

Aahz

unread,
Jun 24, 2002, 10:58:05 PM6/24/02
to
In article <mailman.102495783...@python.org>,

David LeBlanc <whi...@oz.net> wrote:
>
>Does code run at global scope pay a global scope lookup cost?

Yup.

Aahz

unread,
Jun 24, 2002, 10:58:56 PM6/24/02
to
In article <WEuR8.2074$5l4....@ozemail.com.au>,

Dianne van Dulken <dia...@dogmac.com> wrote:
>
>I'm fairly new to python, coming from a perl background, and was wondering
>if anyone has a list of things that they consider as good programming
>practice in Python (I thought this might be an interesting topic for
>discussion, anyway)

In Python 2.1.2 or higher, fire up the interactive interpreter and type
"import this".

Aahz

unread,
Jun 24, 2002, 11:12:45 PM6/24/02
to
In article <3D17C0D0...@engcorp.com>,

Because unless you're using the C API, you can never access the
references directly. Python always hides the references from you:

>>> a = []
>>> b = a
>>> a.append(1)
>>> b
[1]

It's pretty clear that the assignment creates a reference to an object,
rather than having a variable contain the value. It should be equally
clear that the dereferencing is completely automatic -- so automatic, in
fact, that you *can't* get at the reference.

Saying "binding" instead of "reference" helps to remember the critical
semantic differences in Python's object model. It also helps when one
is trying to explain things like this:

def f(a, x=[]):
x.append(a)
print x

f(1)
f('foo')
L=[5]
f(9, L)
f(23)

Aahz

unread,
Jun 24, 2002, 11:16:02 PM6/24/02
to
In article <mailman.102495153...@python.org>,
David LeBlanc <whi...@oz.net> wrote:
>Mark:

>>
>> When evaluating whether a variable is None, don't compare it like this:
>>
>> if x == None:
>>
>> instead, use:
>>
>> if x:
>>
>> or:
>>
>> if not x:
>>
>> The encourages a polymorphic approach. If you must compare to
>> None, use the identify operator rather than equality:
>>
>> if x is None:
>>
>> or:
>>
>> if x is not None:
>
>I'm curious to know how this encourages polymorphism, and how making a
>conditional test implicit rather then explicit is good practice?

Depends on what you're testing for. One of the big features of Python's
object model is that any "empty" object tests as false: None, 0, "", (),
[], and {}. Testing for a specific false value (such as 0 or None)
prevents you from easily changing the object being used. Rely on the
object to tell you whether it's true or false, and you'll be fine.

That's polymorphic.

David LeBlanc

unread,
Jun 24, 2002, 10:30:23 PM6/24/02
to
Grrrr!

Look at it this way:

a,b,c = func()

abc = func()
a = abc[0]
b = abc[1]
c = abc[2]

Which would you rather write? In C or C++ you have to use an analog of the
second way since the first way isn't an option. I _like_ this behavior of
Python.

It's a piddling point as to how Python returns the info - they come to rest
in discrete variables, not as elements of one aggregate variable. The
original point was about the flexibility of Python not some technical
hair-splitting about what Python might put on the stack.

David LeBlanc
Seattle, WA USA

> -----Original Message-----
> From: Peter Hansen [mailto:pe...@engcorp.com]
> Sent: Monday, June 24, 2002 19:28
> To: David LeBlanc
> Subject: Re: Suggestions for good programming practices?
>
>
> David LeBlanc wrote:
> >
> > They may be returned in a tuple, but they're PUT in discrete
> variables and
> > not kept in a tuple that I have to programmatically unpack.
> >
> > Language lawyer should be shot, _then_ heard.
>

> I don't understand the above at all. Sorry. :) Are you
> unhappy with this behaviour of Python? And I don't get
> the language lawyer part. (Pretend I'm really thick...it
> won't be far from the truth.)
>
> -Peter

David LeBlanc

unread,
Jun 24, 2002, 10:24:53 PM6/24/02
to
Structs and tuples are different. They're both of the same general category
of aggregate data, but they are different as Brian notes.

It's like people: boys are people and girls are people, but if you try to
access a strange girl by position, you're apt to get your face smacked or
worse! ;-)

<tongue value='most firmly in cheek'/>

David LeBlanc
Seattle, WA USA

> -----Original Message-----
> From: python-l...@python.org
> [mailto:python-l...@python.org]On Behalf Of Brian Quinlan
> Sent: Monday, June 24, 2002 19:04
> To: 'Peter Hansen'; pytho...@python.org
> Subject: RE: Suggestions for good programming practices?


>
>
> Peter Hansen wrote:
> > Brian Quinlan wrote:
> > >
> > > Peter Hansen wrote:

> > > > You _are_ returning them "in a struct". It's spelled "tuple"
> > > > but other than that what's the difference?
> > >

> > > struct members are access by name while tuple elements are accessed
> > > positionally.
> >
> > Okay. So why is that a problem?
>

> I'm not saying it is. I'm saying that tuples and structs are different.
>
> Cheers,
> Brian
>
>
>

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

Peter Hansen

unread,
Jun 25, 2002, 12:02:24 AM6/25/02
to
David LeBlanc wrote:
>
> Somebody seems to be working overtime to miss the point here...

Don't be rude please. Your offline message pointed out that you
_like_ this behaviour, and so do I, but your original message
appeared to indicate you did not. I was trying to get at
why you didn't like it, not to be pedantic or anything.

David LeBlanc originally wrote:
> The one that always gets me is "lat,lon,timezone =
> getLocation("seattle")". I.E. the ability to return multiple
> distinct values as opposed to returning
> multiple values in the form of a struct as in C or C++.

Sorry for the confusion...

-Peter

Roman Suzi

unread,
Jun 25, 2002, 12:33:34 AM6/25/02
to
On Mon, 24 Jun 2002, David LeBlanc wrote:

>Grrrr!
>
>Look at it this way:
>
> a,b,c = func()
>
> abc = func()
> a = abc[0]
> b = abc[1]
> c = abc[2]
>
>Which would you rather write? In C or C++ you have to use an analog of the
>second way since the first way isn't an option. I _like_ this behavior of
>Python.
>
>It's a piddling point as to how Python returns the info - they come to rest
>in discrete variables, not as elements of one aggregate variable. The
>original point was about the flexibility of Python not some technical
>hair-splitting about what Python might put on the stack.


The 'a,b,c = func()'-style is good as far as there will be
no soon change to the number of variables.

I'd not advice using this style as I fight it now in my own
old scripts...

Now I am using dicts or instances to hold values:
it gives context information:

abc = func()
... use abc["first"]
abc["second"] ...
... abc["third"]

or (in the less trivial cases):

abc = func()
... use abc.first
abc.second ...
... abc.third

Or I am using 'constants' to access return:

FIRST,SECOND,THIRD = range(3)

...

abc = func()
... use abc[FIRST]
abc[SECOND] ...
... abc[THIRD]


- all these allow variable number of returned values thus
keeping compatibility. (for example, I can access old
and new logs by the same code).

Well, to be honest, I am also using this approach:


a,b,c,d,e = (func()+ (None,)*2)[:5]

when originally there were 3 vars and now I sometimes get
3, sometimes 5.
but it is not very nice...

- those my examples aren't probably good programming practices,
but they allow not to loose context when flexibility is needed.

>David LeBlanc
>Seattle, WA USA

Sincerely yours, Roman Suzi
--
r...@onego.ru =\= My AI powered by Linux RedHat 7.2

Roy Smith

unread,
Jun 25, 2002, 7:48:06 AM6/25/02
to
"David LeBlanc" <whi...@oz.net> wrote:
> Structs and tuples are different. They're both of the same general category
> of aggregate data, but they are different as Brian notes.

I've come to really dislike using tuples for data structures, and
instead create small data classes. Even if the class is no more
complicated than:

class myData:
def __init__ (self, foo, bar):
self.foo = foo
self.bar = bar

you've added quite a bit of functionality. First, the code becomes a
little more self-documenting. "power = ckt.volts * ckt.amps" is a lot
easier to read and understand than "power = ckt[0] * ckt[1]".

Secondly, it makes it easier to catch programming errors. I was working
with somebody the other day who was using tuples to store data. His
program was doing something strange. When I made him rewrite one of his
data structures as a simple data class instead of a tuple, the reason
instantly popped out. He had gotten confused and was using the wrong
piece of data. When he had everything as tuples, it just happily took
the i'th element of the wrong tuple and gave him garbage. But, when he
tried to access an attribute that didn't exist, it immediately raised an
exception.

Emile van Sebille

unread,
Jun 25, 2002, 9:27:41 AM6/25/02
to
Aahz

> In Python 2.1.2 or higher, fire up the interactive interpreter and
type
> "import this".

Except ActiveState's

F:\Python22as>python
Python 2.2 (#28, Dec 21 2001, 12:21:22) [MSC 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import this
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ImportError: No module named this

--

Emile van Sebille
em...@fenx.com

---------

Emile van Sebille

unread,
Jun 25, 2002, 10:06:52 AM6/25/02
to
Simon Brunning
> It isn't in the 2.2 series until 2.2.1, IIRC.
>

Am I missing something?

F:\Python22>python


Python 2.2 (#28, Dec 21 2001, 12:21:22) [MSC 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import this

The ...

Jeff Epler

unread,
Jun 25, 2002, 9:34:14 AM6/25/02
to
On Tue, Jun 25, 2002 at 07:48:06AM -0400, Roy Smith wrote:
> "David LeBlanc" <whi...@oz.net> wrote:
> > Structs and tuples are different. They're both of the same general category
> > of aggregate data, but they are different as Brian notes.
>
> I've come to really dislike using tuples for data structures, and
> instead create small data classes. Even if the class is no more
> complicated than:
>
> class myData:
> def __init__ (self, foo, bar):
> self.foo = foo
> self.bar = bar
>
> you've added quite a bit of functionality. First, the code becomes a
> little more self-documenting. "power = ckt.volts * ckt.amps" is a lot
> easier to read and understand than "power = ckt[0] * ckt[1]".

(the following applies most obviously to modern versions of python. I
use subclassing of builtin objects, __slots__ and zip(). Even so, the
myStruct class is useful in any version of Python back to at least 1.5,
if you make myStruct a regular class, and include a definition
of zip())

You can do even better (lower memory overhead) with
class myData(object):
__slots__ = ['foo', 'bar']


def __init__ (self, foo, bar):
self.foo = foo
self.bar = bar

you could go a little farther and make a superclass that has a __init__
that works for any subclass:
class myStruct(object):
def __init__(self, *args):
if len(args) != len(self.__slots__):
raise TypeError, \
"__init__() takes exactly %d arguments (%d given)" \
% (len(self.__slots__)+1, len(args)+1)
for name, arg in zip(self.__slots__, args):
setattr(self, name, arg)

class myData(myStruct):
__slots__ = ['foo', 'bar']

Jeff


Simon Brunning

unread,
Jun 25, 2002, 9:31:48 AM6/25/02
to
> From: Emile van Sebille [SMTP:em...@fenx.com]

> Aahz
> > In Python 2.1.2 or higher, fire up the interactive interpreter and
> type
> > "import this".
>
> Except ActiveState's
>
> F:\Python22as>python

> Python 2.2 (#28, Dec 21 2001, 12:21:22) [MSC 32 bit (Intel)] on win32
> Type "help", "copyright", "credits" or "license" for more information.
> >>> import this
> Traceback (most recent call last):
> File "<stdin>", line 1, in ?
> ImportError: No module named this

It isn't in the 2.2 series until 2.2.1, IIRC.

Cheers,
Simon Brunning
TriSystems Ltd.
sbru...@trisystems.co.uk


-----------------------------------------------------------------------
The information in this email is confidential and may be legally privileged.
It is intended solely for the addressee. Access to this email by anyone else
is unauthorised. If you are not the intended recipient, any disclosure,
copying, distribution, or any action taken or omitted to be taken in
reliance on it, is prohibited and may be unlawful. TriSystems Ltd. cannot
accept liability for statements made which are clearly the senders own.


bru...@tbye.com

unread,
Jun 25, 2002, 10:39:05 AM6/25/02
to
On 25 Jun 2002, Chris Liechti wrote:

> >> * Avoid exec, execfile, eval, and input.
> >
> > Might one ask why? What do you have to know to use them successfully?
>
> where does the string you exec come from? from the user: is he a python
> programmer? could he make subtle errors that break your code and then blame
> you? could it be somebody that like to play tricks with others and insert
> harmful expression or satements (like os.system('rm -fR * /*')? How do you
> handle exceptions, as any exception could be raised by the unknown code
> (hint: 'try: ... except: pass' is bad too...)?
>
> if you don't want to deal with such problems, avoid exec* and eval. they
> are fine for a throw away script, and they're needed when you embedd a
> python interpreter in your app (for this case there is code.interact and
> even better reexec). for all the other cases they're a risk.

This view is a overly extreme. Rather than teaching people to fear certain
features like eval/exec, it's better to explain the risks so that they can
make informed decisions as to when it's wise to use them.

For example, eval/exec are incredibly useful in building mini-languages
based on Python, in which you execute user code in some dictionary that
includes your set of custom functions (you basically end up with a
context-specific superset of Python). I've found this to be very useful in
several production systems (not 'throw away script[s]') as well as in
creating programmable test harnesses for the QA department (the
non-programmer QA engineers aren't scared off because they don't realize
it's programming, and the more technical QA engineers are pleased that
you've built them such a "rich" test harness language...hehehe). Can
malicious users do malicious things? Of course! But that's like saying
Guido should disable os.system!

So... rather than teaching "avoid W!", let's say "be careful with W
because of X, Y, and Z". I still wouldn't use eval/exec on code posted
through a web form, for example, but there are times when they are very
useful and I can use them in good confidence because I understand their
risks.

-Dave

Max M

unread,
Jun 25, 2002, 11:04:42 AM6/25/02
to
Jeff Epler wrote:

>>class myData:
>> def __init__ (self, foo, bar):
>> self.foo = foo
>> self.bar = bar
>>
>>you've added quite a bit of functionality. First, the code becomes a
>>little more self-documenting. "power = ckt.volts * ckt.amps" is a lot
>>easier to read and understand than "power = ckt[0] * ckt[1]".
>
>
> (the following applies most obviously to modern versions of python. I
> use subclassing of builtin objects, __slots__ and zip(). Even so, the
> myStruct class is useful in any version of Python back to at least 1.5,
> if you make myStruct a regular class, and include a definition
> of zip())
>
> You can do even better (lower memory overhead) with
> class myData(object):
> __slots__ = ['foo', 'bar']
> def __init__ (self, foo, bar):
> self.foo = foo
> self.bar = bar


You can also make it even more general:

class MyData:

def __init__(self, **args):
self.__dict__.update(args)

d = MyData(firstName='Max M', lastName='Rasmussen')

print d.firstName, d.lastName

>>> Max M Rasmussen


regards Max M

Simon Brunning

unread,
Jun 25, 2002, 10:16:44 AM6/25/02
to
> From: Emile van Sebille [SMTP:em...@fcfw.fenx.com]
> Simon Brunning
> > It isn't in the 2.2 series until 2.2.1, IIRC.
> >
>
> Am I missing something?
>
> F:\Python22>python

> Python 2.2 (#28, Dec 21 2001, 12:21:22) [MSC 32 bit (Intel)] on win32
> Type "help", "copyright", "credits" or "license" for more information.
> >>> import this
> The ...

Clearly I *didn't* recall correctly...

Chris Barker

unread,
Jun 25, 2002, 12:19:08 PM6/25/02
to
Aahz wrote:
> Depends on what you're testing for.

Exactly. I hardly ever use None to mean false, I tend to use it to mean,
well, "none", or nothing there, as it a value that is not defined yet or
doesn't exist.

> object model is that any "empty" object tests as false: None, 0, "", (),
> [], and {}.

That's part of the problem for me, when I am using numbers, 0 (or 0.0)
is as often as not a perfectly valid number, and should not be
interpreted as false. However as someone mentioned:

if x is None

is preferabale to

if x == None

What you want to know is whether x is bound to None so that's what you
should check for.

-Chris


--
Christopher Barker, Ph.D.
Oceanographer

NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris....@noaa.gov

Aahz

unread,
Jun 25, 2002, 12:26:38 PM6/25/02
to
In article <hd_R8.306964$352.31513@sccrnsc02>,

Emile van Sebille <em...@fenx.com> wrote:
>Aahz
>> In Python 2.1.2 or higher, fire up the interactive interpreter and type
>> "import this".
>
>Except ActiveState's
>
>F:\Python22as>python
>Python 2.2 (#28, Dec 21 2001, 12:21:22) [MSC 32 bit (Intel)] on win32
>Type "help", "copyright", "credits" or "license" for more information.
>>>> import this
>Traceback (most recent call last):
> File "<stdin>", line 1, in ?
>ImportError: No module named this

Interesting. That's an ActiveState bug, pure and simple; this.py is a
normal module in Lib/.

Aahz

unread,
Jun 25, 2002, 12:31:08 PM6/25/02
to
In article <3D18868A...@mxm.dk>, Max M <ma...@mxm.dk> wrote:
>
>You can also make it even more general:
>
>class MyData:
>
> def __init__(self, **args):
> self.__dict__.update(args)
>
>d = MyData(firstName='Max M', lastName='Rasmussen')

My preference is for

class MyData:
pass

d = MyData()
d.firstName = None
d.lastName = 'Aahz'

At the very least, I think you ought to rewrite your example as

d = MyData(
firstName = 'Max M',
lastName = 'Rasmussen
)

David Eppstein

unread,
Jun 25, 2002, 12:49:20 PM6/25/02
to
In article <afa5sc$ptl$1...@panix1.panix.com>, aa...@pythoncraft.com (Aahz)
wrote:

> At the very least, I think you ought to rewrite your example as
>
> d = MyData(
> firstName = 'Max M',
> lastName = 'Rasmussen
> )

I think rewriting it without the syntax error would be even better...

--
David Eppstein UC Irvine Dept. of Information & Computer Science
epps...@ics.uci.edu http://www.ics.uci.edu/~eppstein/

Donn Cave

unread,
Jun 25, 2002, 12:57:37 PM6/25/02
to
Quoth bru...@tbye.com:

| On 25 Jun 2002, Chris Liechti wrote:
(someone said)

| > >> * Avoid exec, execfile, eval, and input.

| This view is a overly extreme. Rather than teaching people to fear certain

| features like eval/exec, it's better to explain the risks so that they can
| make informed decisions as to when it's wise to use them.

It's not overly extreme! It's just about extreme enough.

| So... rather than teaching "avoid W!", let's say "be careful with W
| because of X, Y, and Z". I still wouldn't use eval/exec on code posted
| through a web form, for example, but there are times when they are very
| useful and I can use them in good confidence because I understand their
| risks.

But you weren't going to be deterred by that pronouncement anyway.

"Avoid exec, execfile, eval, and input" is good advice. Taken at face
value, it doesn't necessarily absolutely prohibit their use - if I said
"avoid walking in the road", you could reasonably reasonably assume I'm
saying something like "walk on the sidewalk when possible".

Someone whose software engineering skills have been honed by years
of wrestling with ugly code monsters will apply a different perspective
to that advice. A 1-week newbie could do worse than to follow that
advice religiously.

Donn Cave, do...@u.washington.edu

Bjorn Pettersen

unread,
Jun 25, 2002, 12:53:44 PM6/25/02
to
> From: Aahz [mailto:aa...@pythoncraft.com]
>
> In article <hd_R8.306964$352.31513@sccrnsc02>,
> Emile van Sebille <em...@fenx.com> wrote:
> >Aahz
> >> In Python 2.1.2 or higher, fire up the interactive interpreter and
> >> type "import this".
> >
> >Except ActiveState's
> >
> >F:\Python22as>python
> >Python 2.2 (#28, Dec 21 2001, 12:21:22) [MSC 32 bit (Intel)]
> on win32
> >Type "help", "copyright", "credits" or "license" for more
> information.
> >>>> import this
> >Traceback (most recent call last):
> > File "<stdin>", line 1, in ?
> >ImportError: No module named this
>
> Interesting. That's an ActiveState bug, pure and simple;
> this.py is a normal module in Lib/.

It's been fixed in the latest version.

-- bjorn


bru...@tbye.com

unread,
Jun 25, 2002, 2:52:50 PM6/25/02
to
On 25 Jun 2002, Donn Cave wrote:

> | So... rather than teaching "avoid W!", let's say "be careful with W
> | because of X, Y, and Z". I still wouldn't use eval/exec on code posted
> | through a web form, for example, but there are times when they are very
> | useful and I can use them in good confidence because I understand their
> | risks.
>
> But you weren't going to be deterred by that pronouncement anyway.
>
> "Avoid exec, execfile, eval, and input" is good advice. Taken at face
> value, it doesn't necessarily absolutely prohibit their use - if I said
> "avoid walking in the road", you could reasonably reasonably assume I'm
> saying something like "walk on the sidewalk when possible".

If you mean the latter, say the latter. Neither newbies nor veterans have
to do any reading between the lines. Even better, say "walk on the
sidewalk when possible because ___".

> Someone whose software engineering skills have been honed by years
> of wrestling with ugly code monsters will apply a different perspective
> to that advice. A 1-week newbie could do worse than to follow that
> advice religiously.

I understand your point, but the OP is new to Python, not programming.
This isn't a big deal; I was simply pointing out that just saying "don't
use those!" (Why? Are they broken? Deprecated? What?) isn't as helpful as
explaining the risks.

In the specific case of exec/eval, people are quick to strike them down,
often citing the untrusted input example (what about os.system, .fork,
etc.?), but that's a pretty narrow and uncommon usage scenario. When I
first learned Python I used them in some of the "forbidden" ways because I
hadn't learned getattr/setattr yet. So what? My programs worked fine (a
little slow) and later I learned better ways and now use those instead.

If a person is new to programming altogether then what kind of a teacher
will draw attention to exec/eval in the first place anyway? Besides, the
people who understand the potential for problems with something tend to be
the ones that don't mishandle it (whether it be streets, guns, or Python
functions).

-Dave

Bengt Richter

unread,
Jun 25, 2002, 3:14:22 PM6/25/02
to
On 24 Jun 2002 23:16:02 -0400, aa...@pythoncraft.com (Aahz) wrote:

>In article <mailman.102495153...@python.org>,
>David LeBlanc <whi...@oz.net> wrote:
>>Mark:
>>>
>>> When evaluating whether a variable is None, don't compare it like this:
>>>
>>> if x == None:
>>>
>>> instead, use:
>>>
>>> if x:
>>>
>>> or:
>>>
>>> if not x:
>>>
>>> The encourages a polymorphic approach. If you must compare to
>>> None, use the identify operator rather than equality:
>>>
>>> if x is None:
>>>
>>> or:
>>>
>>> if x is not None:
>>
>>I'm curious to know how this encourages polymorphism, and how making a
>>conditional test implicit rather then explicit is good practice?
>
>Depends on what you're testing for. One of the big features of Python's
>object model is that any "empty" object tests as false: None, 0, "", (),
>[], and {}. Testing for a specific false value (such as 0 or None)
>prevents you from easily changing the object being used. Rely on the
>object to tell you whether it's true or false, and you'll be fine.
>
>That's polymorphic.

This kind of usage seems common:

>>> def foo(x=None):
... if x: print "Aahz says we'll be fine with %s" % `x`
... else: print "But what about %s ?" % `x`
... if x is None: print "Here we know we were passed %s (maybe by default)" % `x`
...
>>> foo('something')
Aahz says we'll be fine with 'something'
>>> foo(0)
But what about 0 ?
>>> foo()
But what about None ?
Here we know we were passed None (maybe by default)

Do you recommend using def foo(*args) and testing len(args) instead?

Regards,
Bengt Richter

Bengt Richter

unread,
Jun 25, 2002, 3:32:12 PM6/25/02
to
On Mon, 24 Jun 2002 18:55:22 -0700, "David LeBlanc" <whi...@oz.net> wrote:

>They may be returned in a tuple, but they're PUT in discrete variables and

ITYM bound to discrete variable names

>not kept in a tuple that I have to programmatically unpack.
>

Right, it's programmatically done for you ;-)

>>> def foo(): return (1,2,3)
...
>>> a,b,c = foo()
>>> a
1
>>> b
2
>>> c
3
>>> import dis
>>> dis.dis(foo)
0 SET_LINENO 1

3 SET_LINENO 1
6 LOAD_CONST 1 (1)
9 LOAD_CONST 2 (2)
12 LOAD_CONST 3 (3)
15 BUILD_TUPLE 3
18 RETURN_VALUE
19 LOAD_CONST 0 (None)
22 RETURN_VALUE

>>> from miscutil import disex
>>> disex('a,b,c = foo()')
0 SET_LINENO 0

3 SET_LINENO 1
6 LOAD_NAME 0 (foo)
9 CALL_FUNCTION 0
12 UNPACK_SEQUENCE 3
15 STORE_NAME 1 (a)
18 STORE_NAME 2 (b)
21 STORE_NAME 3 (c)
24 LOAD_CONST 0 (None)
27 RETURN_VALUE

Note the "UNPACK_SEQUENCE" and "STORE_NAME"s.

>Language lawyer should be shot, _then_ heard.

Along with top-posters? ;-)

>
>David LeBlanc
>Seattle, WA USA
>
>> -----Original Message-----
>> From: python-l...@python.org
>> [mailto:python-l...@python.org]On Behalf Of Peter Hansen
>> Sent: Monday, June 24, 2002 18:03
>> To: pytho...@python.org
>> Subject: Re: Suggestions for good programming practices?
>>
>>
>> David LeBlanc wrote:
>> >
>> > The one that always gets me is "lat,lon,timezone =
>> getLocation("seattle")".
>> > I.E. the ability to return multiple distinct values as opposed
>> to returning
>> > multiple values in the form of a struct as in C or C++.
>>
>> You _are_ returning them "in a struct". It's spelled "tuple"
>> but other than that what's the difference?
>>
>> -Peter
>> --
>> http://mail.python.org/mailman/listinfo/python-list
>
>
>

Regards,
Bengt Richter

Bengt Richter

unread,
Jun 25, 2002, 3:46:54 PM6/25/02
to
On Tue, 25 Jun 2002 14:31:48 +0100, Simon Brunning <SBru...@trisystems.co.uk> wrote:

>> From: Emile van Sebille [SMTP:em...@fenx.com]
>> Aahz
>> > In Python 2.1.2 or higher, fire up the interactive interpreter and
>> type
>> > "import this".
>>
>> Except ActiveState's
>>
>> F:\Python22as>python
>> Python 2.2 (#28, Dec 21 2001, 12:21:22) [MSC 32 bit (Intel)] on win32
>> Type "help", "copyright", "credits" or "license" for more information.
>> >>> import this
>> Traceback (most recent call last):
>> File "<stdin>", line 1, in ?
>> ImportError: No module named this
>
>It isn't in the 2.2 series until 2.2.1, IIRC.
>

I think it must be a distribution glitch. My 2.2 banner looks identical:

Python 2.2 (#28, Dec 21 2001, 12:21:22) [MSC 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import this

The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
...

Regards,
Bengt Richter

Carl Banks

unread,
Jun 25, 2002, 3:49:04 PM6/25/02
to
bru...@tbye.com wrote:
> On 25 Jun 2002, Donn Cave wrote:
>
>> | So... rather than teaching "avoid W!", let's say "be careful with W
>> | because of X, Y, and Z". I still wouldn't use eval/exec on code posted
>> | through a web form, for example, but there are times when they are very
>> | useful and I can use them in good confidence because I understand their
>> | risks.
>>
>> But you weren't going to be deterred by that pronouncement anyway.
>>
>> "Avoid exec, execfile, eval, and input" is good advice. Taken at face
>> value, it doesn't necessarily absolutely prohibit their use - if I said
>> "avoid walking in the road", you could reasonably reasonably assume I'm
>> saying something like "walk on the sidewalk when possible".
>
> If you mean the latter, say the latter. Neither newbies nor veterans have
> to do any reading between the lines. Even better, say "walk on the
> sidewalk when possible because ___".

Fair enough.

* Avoid using exec, execfile, eval, and input unless you are
deliberately asking your user to supply Python code, and take
serious precautions if the program is running at a higher privledge
level than the user. All other uses of them should be thoroughly
thought out, and the implications understood.


>> Someone whose software engineering skills have been honed by years
>> of wrestling with ugly code monsters will apply a different perspective
>> to that advice. A 1-week newbie could do worse than to follow that
>> advice religiously.
>
> I understand your point, but the OP is new to Python, not programming.
> This isn't a big deal; I was simply pointing out that just saying "don't
> use those!" (Why? Are they broken? Deprecated? What?) isn't as helpful as
> explaining the risks.
>
> In the specific case of exec/eval, people are quick to strike them down,
> often citing the untrusted input example (what about os.system, .fork,
> etc.?), but that's a pretty narrow and uncommon usage scenario.

I completely disagree. I've seen at least two potentially
security-compromizing uses of eval posted here in the last few days as
"good" ways to do something.

I imagine most people see eval and think, "what a cool, easy way to
turn a string into a list!" without stopping to consider that it could
also turn a string into a syntax error, or an object that erases your
whole filesystem when its __getitem__ method is called.


> When I
> first learned Python I used them in some of the "forbidden" ways because I
> hadn't learned getattr/setattr yet. So what? My programs worked fine (a
> little slow) and later I learned better ways and now use those instead.

You were lucky that your forbidden uses of eval and exec weren't
dangerous in that case. (Or maybe you weren't lucky but were already
aware that eval could be dangerous, but that's not the case for all
newbies.)


> If a person is new to programming altogether then what kind of a teacher
> will draw attention to exec/eval in the first place anyway?

A good one. Realizing that one does not need to call attention to
eval for a newbie to find it, a good teacher explains that it is
dangerous before the newbie has a chance to hurt himself with it.


> Besides, the
> people who understand the potential for problems with something tend to be
> the ones that don't mishandle it (whether it be streets, guns, or Python
> functions).

Which is why it is important to tell people who don't understand the
potential for problems to not use eval until they do.

You seem to have this idea, based on this last paragraph, that a good
way to keep newbies from misusing eval and exec is to keep them in
ignorance. I think that's absurd. I don't know if you're just
grasping for arguments, because you previously seemed to think it's
best to explain WHY, as opposed to simply saying, "Don't do it."


--
CARL BANKS http://www.aerojockey.com
"Nullum mihi placet tamquam provocatio magna. Hoc ex eis non est."

bru...@tbye.com

unread,
Jun 25, 2002, 6:10:40 PM6/25/02
to
On Tue, 25 Jun 2002, Carl Banks wrote:

> > Besides, the
> > people who understand the potential for problems with something tend to be
> > the ones that don't mishandle it (whether it be streets, guns, or Python
> > functions).
>
> Which is why it is important to tell people who don't understand the
> potential for problems to not use eval until they do.
>
> You seem to have this idea, based on this last paragraph, that a good
> way to keep newbies from misusing eval and exec is to keep them in
> ignorance. I think that's absurd. I don't know if you're just
> grasping for arguments, because you previously seemed to think it's
> best to explain WHY, as opposed to simply saying, "Don't do it."

Um, what's absurd is how you reached that conclusion from the paragraph I
wrote. <0.4 wink> I said that people WON'T get hurt if they are NOT
ignorant - I'm advocating an explanation of risk in place of the
categorical "stay away!".

-Dave

Aahz

unread,
Jun 25, 2002, 5:49:38 PM6/25/02
to
In article <afafee$fc$0...@216.39.172.122>, Bengt Richter <bo...@oz.net> wrote:
>
>Do you recommend using def foo(*args) and testing len(args) instead?

Only if you really want a list of unnamed parameters. Personally, I
usually prefer to pass a sequence directly in such cases, to distinguish
between None (i.e. no list) and the empty list.

Carl Banks

unread,
Jun 25, 2002, 6:13:41 PM6/25/02
to

What's really absurd is how you reached the conclusion that I reached
a conclusion when I only said, "you seem to." <wink> So why did you
ask what kind of teacher calls a newbie's attention to eval? You
seemed (not to be confused with "I have concluded") to have been
advocating ignorance.

Are you merely saying it's better to say nothing than to say, "don't
do this?" Because I would disagree with that, too.

Bengt Richter

unread,
Jun 25, 2002, 8:53:22 PM6/25/02
to
On 25 Jun 2002 17:49:38 -0400, aa...@pythoncraft.com (Aahz) wrote:

>In article <afafee$fc$0...@216.39.172.122>, Bengt Richter <bo...@oz.net> wrote:
>>
>>Do you recommend using def foo(*args) and testing len(args) instead?
>
>Only if you really want a list of unnamed parameters. Personally, I
>usually prefer to pass a sequence directly in such cases, to distinguish
>between None (i.e. no list) and the empty list.

Well, I meant using *args to allow detecting actual "no default-overriding
argument passed", in place of x=None. The arg list items (only x here)
don't have to remain unnamed long. E.g.,

>>> def foo(*args):
... if len(args)==1:
... print "We know we have one non-default arg: %s" % `args[0]`
... x = args[0]
... elif len(args)==0:
... print "We can supply a default arg, even None"
... x = None
... else: raise TypeError,'foo() takes 0 or 1 arguments (%d given)' % len(args)
... print 'Effective arg was: %s' % `x`
...
>>> foo('one arg')
We know we have one non-default arg: 'one arg'
Effective arg was: 'one arg'
>>> foo(None)
We know we have one non-default arg: None
Effective arg was: None
>>> foo()
We can supply a default arg, even None
Effective arg was: None
>>> foo(None,'too many')


Traceback (most recent call last):
File "<stdin>", line 1, in ?

File "<stdin>", line 8, in foo
TypeError: foo() takes 0 or 1 arguments (2 given)

Hm. It occurs to me that *args also lets you put defaults at the front if you like,
and specify not just min and max number of args. E.g., a textout method could
use current x,y by default or allow override (obviously this example is just
about parameter passing, not graphics output. And no prizes for speed ;-)

>>> class GX:
... def __init__(self, x, y): self.x, self.y = x,y
... def textout(self, *args):
... if len(args) not in (1,3):
... raise TypeError,"Use textout('string') or textout(x,y,'string') (%d args given)" % len(args)
... if len(args)==1:
... x, y, a = self.x, self.y, args[0]
... else:
... x, y, a = args
... print 'output "%s" at %s,%s' % (a, x, y)
...
>>> g=GX(123, 456)
>>> g.textout('using curr pos')
output "using curr pos" at 123,456
>>> g.textout(333, 444, 'using spec pos')
output "using spec pos" at 333,444

And accurate arg count validation can be had (ignoring types):
>>> g.textout()


Traceback (most recent call last):
File "<stdin>", line 1, in ?

File "<stdin>", line 5, in textout
TypeError: Use textout('string') or textout(x,y,'string') (0 args given)
>>> g.textout(1,2)


Traceback (most recent call last):
File "<stdin>", line 1, in ?

File "<stdin>", line 5, in textout
TypeError: Use textout('string') or textout(x,y,'string') (2 args given)
>>> g.textout(1,2,3,4)


Traceback (most recent call last):
File "<stdin>", line 1, in ?

File "<stdin>", line 5, in textout
TypeError: Use textout('string') or textout(x,y,'string') (4 args given)

Regards,
Bengt Richter

Jonathan Hogg

unread,
Jun 26, 2002, 5:20:38 AM6/26/02
to
On 26/6/2002 1:53, in article afb3a2$skm$0...@216.39.172.122, "Bengt Richter"
<bo...@oz.net> wrote:

> Well, I meant using *args to allow detecting actual "no default-overriding
> argument passed", in place of x=None. The arg list items (only x here)
> don't have to remain unnamed long. E.g.,
>
>>>> def foo(*args):
> ... if len(args)==1:
> ... print "We know we have one non-default arg: %s" % `args[0]`
> ... x = args[0]
> ... elif len(args)==0:
> ... print "We can supply a default arg, even None"
> ... x = None
> ... else: raise TypeError,'foo() takes 0 or 1 arguments (%d given)' %
> len(args)
> ... print 'Effective arg was: %s' % `x`
> ...

I find this stuff much easier to write with a helper function:

>>> def shift():
... global _0
... __, _0 = _0[0], _0[1:]
... return __
...

Then I can write the function 'foo' much more naturally as:

>>> def foo( *args ):
... global _0; _0 = args
... try:
... x = shift()
... except IndexError:


... print 'We can supply a default arg, even None'
... x = None
... else:

... try:
... shift()
... except IndexError:
... print 'We know we have one non-default arg: %s' % `x`
... else:
... raise TypeError( 'foo() takes 0 or 1 arguments' )


... print 'Effective arg was: %s' % `x`
...

This can be further simplified by removing the '*args' nonsense altogether
and defining another helper function:

>>> def p( f ):
... def _p( *args ): global _0; _0 = args; f()
... return _p
...
>>> def foo():
... try:
... x = shift()
[etc]
...
>>> p(foo)( 'hello world' )

How did we get onto this from 'Suggestions for good programming practices'?

Jonathan

bru...@tbye.com

unread,
Jun 26, 2002, 11:03:54 AM6/26/02
to
On Tue, 25 Jun 2002, Carl Banks wrote:

> So why did you ask what kind of teacher calls a newbie's attention to
> eval? You seemed (not to be confused with "I have concluded") to have
> been advocating ignorance.

Nope. Just like on the first day of a C programming class, a lousy teacher
would say, "Avoid pointers to pointers!" - it doesn't help at all to bring
that up so early in the learning process, it's confusing, and those types
of problems are furthest from the students' minds (they're interesting in
*doing* something with this new language). There's a host of other things
that are more useful to a newbie, whether experienced in other languages
or not. But *if* you do bring it up, then you should take the time to
explain why it's potentially bad.

Likewise, it doesn't really help a newbie much to bring up eval/exec right
away and say, "don't use this!" because there's tons of other things that
will help them so much more, and in the early learning stages they're not
going to be hurt by using those functions anyway. But *if* you do bring
those functions up and advise against using them, you should explain why.

And if your code will be running in an environment where it might be used
maliciously, you need more than "don't use exec/eval" anyway - you really
need to take some time to learn about basic program security as there are
plenty of other potential security holes (at the very least you need a
security mini-FAQ or checkoff list in which exec/eval would be listed
along with many other things). With that knowledge you'd discover the
risk of eval/exec on your own - they'd jump right out at you with even
just a quick security audit.

-Dave

Bengt Richter

unread,
Jun 26, 2002, 3:53:44 PM6/26/02
to

LOL ;-)

>
>How did we get onto this from 'Suggestions for good programming practices'?
>

I guess from where I picked up: x=None usage => default args => alternatives => rambling on ...
=> *args use analogous to C++ void foo(const char* s){...}; and
void foo(const int x, const int y, const char* s){...}; to allow foo("s only") and
foo(123, 456, "s with ints") overloading via Python dynamic recognition instead of statically
via C++ ?foo@@YAXPBD@Z vs ?foo@@YAXHHPBD@Z => non-Python odor? => Bad Thing(tm) or caller-friendly?

ISTM caller-friendly is good, but the *args implementation of this overloading is not as nice
as it could be. Is it better to allow foo(x,y,s) and foo(s) via overloaded foo() than, e.g.,
to use separate names like fooxy(x,y,s) and foo(s), and have foo() call fooxy()?
(That, at least, is an OT question ;-)

Regards,
Bengt Richter

Quinn Dunkan

unread,
Jun 27, 2002, 1:47:40 AM6/27/02
to
On Mon, 24 Jun 2002 18:55:22 -0700, David LeBlanc <whi...@oz.net> wrote:
>They may be returned in a tuple, but they're PUT in discrete variables and
>not kept in a tuple that I have to programmatically unpack.
>
>Language lawyer should be shot, _then_ heard.

So you'd prefer whole threads like this:


> > AAAAAAAAAAAAAAAAAAAAAaaaaaaaaaaaahhhhhhhhhhhhhhhhhhhhhhhh
> >
> > .
> >
> > .
> >
> > .
> >
> > *gurgle*
>
> *hurk* ... *thud*

Yaaaaaaahhhhhh!!!!! *wheeze* SHRIEK!!

Quinn Dunkan

unread,
Jun 27, 2002, 1:53:29 AM6/27/02
to
On Mon, 24 Jun 2002 16:31:14 -0500, Mark McEahern <mark...@mceahern.com>
wrote:
>How do you choose between these:
>
> if x is None:
>
> if x:
>
>The latter is what you'd use if you wanted to work with instances that
>defined __nonzero__ and or __len__. In other words, you don't really care
>what the type of x is, nor whether it's identity is zero, just whether it
>considers itself nonzero.
>
>Is one more or less polymorphic than the other? I don't really know. But
>it sure does sound good.

They both serve their own purposes and you have to know what you want.

For example, I recently tracked down an annoying bug where I said 'if x' when
I meant 'if x is not None'. Everything worked until x's __len__ returned 0
and it was hard for me to see 'if x' as being buggy code. I wasted a lot of
time trying to figure out why 'x' was occaisionally None.

Jonathan Hogg

unread,
Jun 27, 2002, 9:18:40 AM6/27/02
to
On 26/6/2002 20:53, in article afd648$3b4$0...@216.39.172.122, "Bengt Richter"
<bo...@oz.net> wrote:

> LOL ;-)

It continually amazes me that Python is so backward as to require the
programmer to explicitly note that a function takes arguments ;-)

> ISTM caller-friendly is good, but the *args implementation of this overloading
> is not as nice
> as it could be. Is it better to allow foo(x,y,s) and foo(s) via overloaded
> foo() than, e.g.,
> to use separate names like fooxy(x,y,s) and foo(s), and have foo() call
> fooxy()?
> (That, at least, is an OT question ;-)

I'm of the opinion that when a function can take a sensible set of unrelated
optional arguments they should be keyword arguments, and one should call the
function with those keywords explicitly:

>>> def writeString( s, x=0, y=0 ):
... pass
...
>>> writeString( "Hello World" )
>>> writeString( "This is a test", x=10, y=35 )
>>>

When the function can take a variable number of related arguments, I use
*args:

>>> def writeStrings( *strings ):
... for s in strings:
... writeString( s )
...
>>> writeStrings( "Hello World" )
>>> writeStrings( "This is a test", "I love tests" )
>>>

These styles, of course, can be mixed. I'm not a big fan of the idea of
distinguishing between not supplying an optional argument and supplying the
equivalent default. I think a default should mean a default, not an
indicator of no-argument. I don't much like:

>>> def writeString( s, x=None, y=None ):


... if x is None:

... # do something else
... pass
... pass
...

I think that calling a function with a default argument explicitly given
should always make sense, i.e., read sensibly. So:

>>> writeString( "This is a test", x=None, y=None )
>>>

doesn't feel right to me since I'm not convinced that 'None' makes sense as
a position. If the default is being used to indicate, for example, the
current cursor position, then it should be explicitly named like:

>>> class _CurrentPosition: pass
...
>>> CurrentPosition = _CurrentPosition()
>>>
>>> def writeString( s, x=CurrentPosition, y=CurrentPosition ):
... if x is CurrentPosition:
... # obtain current x co-ordinate
... pass
... pass
...
>>> writeString( "Hello World", x=CurrentPosition, y=CurrentPosition )
>>>

The exception that proves the rule is where None really is a sensible
default.

Hoo hah. That's enough of that.

Jonathan

KP2 KP2

unread,
Feb 11, 2024, 9:09:26 PMFeb 11
to
On Tuesday, June 25, 2002 at 4:48:06 AM UTC-7, Roy Smith wrote:
> "David LeBlanc" <whi...@oz.net> wrote:
> > Structs and tuples are different. They're both of the same general category
> > of aggregate data, but they are different as Brian notes.
> I've come to really dislike using tuples for data structures, and
> instead create small data classes. Even if the class is no more
> complicated than:
> class myData:
> def __init__ (self, foo, bar):
> self.foo = foo
> self.bar = bar
> you've added quite a bit of functionality. First, the code becomes a
> little more self-documenting. "power = ckt.volts * ckt.amps" is a lot
> easier to read and understand than "power = ckt[0] * ckt[1]".
> Secondly, it makes it easier to catch programming errors. I was working
> with somebody the other day who was using tuples to store data. His
> program was doing something strange. When I made him rewrite one of his
> data structures as a simple data class instead of a tuple, the reason
> instantly popped out. He had gotten confused and was using the wrong
> piece of data. When he had everything as tuples, it just happily took
> the i'th element of the wrong tuple and gave him garbage. But, when he
> tried to access an attribute that didn't exist, it immediately raised an
> exception.
2
0 new messages