Re: Python help

2004-02-09 Thread Erik Price
On Feb 8, 2004, at 9:31 PM, [EMAIL PROTECTED] wrote:

Java requires even more verbosity.
This is my general impression of Java.  Is the verbosity a good thing
or not?  It seems verbose to the point of redundancy.  Is this
helpful, or does it just get in the way?
The answer to that is that it's a matter of perspective, but I don't 
think that Java would be as successful as it is if a majority of people 
found it -too- redundant.  There's no doubt about it -- the verbosity 
of Java is overkill for simpler tasks like what you've accomplished 
with your Python script, especially when there are languages like 
Python, Perl, Ruby, and bash which can make this kind of thing a lot 
easier.  And, if you know you'll only ever invoke the program on a Unix 
machine, you can do what another poster suggested and simply glue a 
bunch of existing Unix tools together like awk, sed, grep, find, et 
cetera, reducing the burden of actually programming the task to a level 
of merely asking other tools to perform certain actions on the text.  
But when things get a bit more complicated, this verbosity can be 
helpful.  (see below)


It took longer to write, even though I had already
prototyped the design in Python (the two designs are nearly 
identical),
Was it just the verbosity of Java which made it take so long?
Yes and no.  No if you mean did the verbosity take longer to type.  
Yes, because Java requires a great deal more syntax to say the same 
thing that can be said with less syntax in Python, and subtle issues 
surfaced when trying to compile the code and then run it.  For 
instance, there were numerous times I was attempting to use a class 
without having imported it first.  Another thing is that the verbosity 
of Java means that there is more text to be conscious of using 
correctly, so that right there leads to greater potential to make a 
mistake.

I wrote that Java implementation in a text editor, which is a useable 
but relatively primitive tool for a language that can be as verbose as 
Java.  It would have been faster to use an IDE.  At work we use WSAD, 
which speeds development by automatically importing any classes I 
attempt to use, automatic method completion, popup API documentation 
(sparing me a trip to the docs), realtime compiler error-checking, and 
other luxuries.  So, using a text editor, I'd make a change and then 
jump back to the shell and type the command to compile the file.  This 
doesn't take long, because I use keyboard shortcuts and the command 
history, but then I have to examine the compiler output when there's a 
problem and jump back to the text editor and fix the mistake -- an IDE 
will highlight the erroneous code, making it much faster to figure out 
what you've done wrong.

But Python offers the interactive interpreter, which is a godsend when 
trying to debug a problem or even just sketching out the script.  If 
you write a python script and invoke it with the -i option (python -i 
scriptname), then after the script completes you are automatically 
dumped into the interactive interpreter and any variables in your 
script are now local to your python session so you can invoke functions 
using arbitrary arguments, evaluate the values of variables, and other 
conveniences.

(Yeah, I know that Real Programmers (tm) use vi/emacs/ed, but Real 
Programmers also don't consider Java  a Real Programming Language. ;)

and IMHO would also be more work to modify/extend.  That said, if
handed a several million-line application written by some other
development team, I would rather the application be written in Java
than Python.
Why?  Performance, cleaner code, more robust language?  What makes
Java better than Python for some things?  What types of things is
Java best at?
In this particular case, the reason I say that is because Java is a 
statically typed language, and Python is dynamically typed.  There are 
a lot of arguments about which is better, and I won't say one is better 
than the other for all occasions -- but I happen to find a statically 
typed language like Java to be easier to read once the application 
exceeds a certain level of complexity.  I anticipate some dissent on 
this topic, mind you.  But when I'm trying to navigate my way through a 
twisted legacy framework of poorly-written source code to find a bug, 
it's nice to see the type declarations reminding me that foo is a 
FileManager and bar is a BufferedXmlMessage.

Of course, static type declarations are a pain in the ass in smaller 
programs, or programs that I'll be writing entirely myself, since I 
can't enjoy such flexibilities as this:

for item in iterableSequence:
item.doSomething()
Where iterableSequence could be a reference to a file object (so item 
would be a line), or a database resultset object (so item would be a 
row), or an object representing a list of users (so item would be a 
user), etc.  Unlike Java, Python doesn't require that your objects 
actually declare that they implement a specific 

Re: Python help

2004-02-08 Thread p . lussier

In a message dated: Sat, 07 Feb 2004 09:33:19 EST
Erik Price said:

Here's the Java implementation.

Very cool!  Thanks!

 Java requires even more verbosity.

This is my general impression of Java.  Is the verbosity a good thing 
or not?  It seems verbose to the point of redundancy.  Is this 
helpful, or does it just get in the way?

It took longer to write, even though I had already 
prototyped the design in Python (the two designs are nearly identical), 

Was it just the verbosity of Java which made it take so long?

and IMHO would also be more work to modify/extend.  That said, if 
handed a several million-line application written by some other 
development team, I would rather the application be written in Java 
than Python.

Why?  Performance, cleaner code, more robust language?  What makes 
Java better than Python for some things?  What types of things is
Java best at?

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

This almost seems rediculous :)  9 library imports, it seems that 
some should be so commonly used that they'd just be built-in
or at least combined into something like stdio.

Thanks a bunch.  Part of trouble with learning languages is the lack 
of real world applications to try them out with.  One reason I know 
perl so well is because the language is designed to do exactly what I 
do all the time; text munging.  Something C and Java aren't 
especially efficient at it seems :)


-- 

Seeya,
Paul
--
Key fingerprint = 1660 FECC 5D21 D286 F853  E808 BB07 9239 53F1 28EE

It may look like I'm just sitting here doing nothing,
   but I'm really actively waiting for all my problems to go away.

 If you're not having fun, you're not doing it right!


___
gnhlug-discuss mailing list
[EMAIL PROTECTED]
http://mail.gnhlug.org/mailman/listinfo/gnhlug-discuss


Re: Python help

2004-02-07 Thread Erik Price
On Feb 5, 2004, at 10:47 AM, Paul Lussier wrote:

I'm not overly interesting in shell, perl, tcl, or other language 
solutions
to this problem, since I already know how to write this in the first 3.
(a java or c implementation might be interesting :)
Here's the Java implementation.  You can see that the way I went about 
it is just like the Python version, except Java requires even more 
verbosity.  It took longer to write, even though I had already 
prototyped the design in Python (the two designs are nearly identical), 
and IMHO would also be more work to modify/extend.  That said, if 
handed a several million-line application written by some other 
development team, I would rather the application be written in Java 
than Python.



import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
class Group {

private static final int NAME_INDEX = 0;
private static final int GID_INDEX = 2;
private static final int MEMBERS_INDEX = 3;
private String name;
private int gid;
private List members;
Group(String name, int gid, List members) {

this.name = name;
this.gid = gid;
this.members = members;
}

Group (String lineFromFile) {

String[] record = lineFromFile.split(:);
this.name = record[NAME_INDEX];
this.gid = Integer.parseInt(record[GID_INDEX]);
if (hasMembers(record)) {
String[] membersArray =
record[MEMBERS_INDEX].split(,);
this.members = Arrays.asList(membersArray);
}
}

private boolean hasMembers(String[] record) {
return (record.length == MEMBERS_INDEX + 1);
}
String toLdifFormat() {

String memberString = ;

if (this.members != null) {
SortedSet sorted = new TreeSet(this.members);
for (Iterator i = sorted.iterator(); i.hasNext();) {
memberString += (String)i.next();
if (i.hasNext()) {
memberString += ,;
}
}
}
return this.name + : + this.gid + : + memberString;
}
}





public class EtcGroupToLdif {

public static void main(String[] args) throws IOException {

File etcGroup = new File(args[0]);
BufferedReader br =
new BufferedReader(new FileReader(etcGroup));
String line;
while ((line = br.readLine()) != null) {
if (line.startsWith(#)) {
continue;
}
Group group = new Group(line);
System.out.println(group.toLdifFormat());
}

br.close();

}
}
___
gnhlug-discuss mailing list
[EMAIL PROTECTED]
http://mail.gnhlug.org/mailman/listinfo/gnhlug-discuss


Re: Python help

2004-02-06 Thread Erik Price
 
On Thursday, February 05, 2004, at 06:14PM, Cole Tuininga [EMAIL PROTECTED] wrote:


This is a very subtle one.  The point is that in a method definition
within an object, you never want to assign a mutable type (namely, the
empty list) to an argument.  Weird behavior will occur.

I totally forgot about that!  Excellent observation.  According to the language 
reference, it's because:

explanation src =http://python.org/doc/current/ref/function.html;

Default parameter values are evaluated when the function definition is executed. This 
means that the expression is evaluated once, when the function is defined, and that 
that same ``pre-computed'' value is used for each call. This is especially important 
to understand when a default parameter is a mutable object, such as a list or a 
dictionary: if the function modifies the object (e.g. by appending an item to a list), 
the default value is in effect modified. This is generally not what was intended.

/explanation

 def main(args=sys.argv):

One point about the above line - if you're testing from a python prompt,
you'll need to pass your arguments in as a list.  So for instance,
 main( [/etc/group] )

rather than just

 main ( /etc/group )

Otherwise, the next line would generate some rather peculiar behavior.

 f = file(args[1], r)

Yes, exactly.  Although, I think you meant that the file name should be in the second 
element of the list passed into the main() function, because in sys.argv the first 
element (sys.argv[0]) is the script name, and arguments start at sys.argv[1].

Also, below, it looks like you started out wanting to use a list, but
switched to a dict:

Yes, I started out by reproducing Paul's original script (which used a dict) exactly, 
and then I refactored the dict to a list when I realized that the main() function 
didn't really need to know the Group object's name anymore.  I should have tested this 
code, but I was in a rush.

These items aren't meant as bashing - I know you said you wrote it
without testing.  I'm just trying to clarify.  8)

Not at all.  Thanks for your input, esp about the mutable default argument in a class 
method declaration.  And, my apologies to the list for sending the email thrice; mail 
client problems.


Erik
___
gnhlug-discuss mailing list
[EMAIL PROTECTED]
http://mail.gnhlug.org/mailman/listinfo/gnhlug-discuss


Re: Python help

2004-02-06 Thread Cole Tuininga
On Fri, 2004-02-06 at 09:12, Erik Price wrote:

  def main(args=sys.argv):
 
 One point about the above line - if you're testing from a python 
 prompt,
 you'll need to pass your arguments in as a list.  So for instance,
  main( [/etc/group] )
 
 rather than just
 
  main ( /etc/group )
 
 Otherwise, the next line would generate some rather peculiar behavior.
 
  f = file(args[1], r)
 
 Yes, exactly.  Although, I think you meant that the file name should 
 be in the second element of the list passed into the main() function, 
 because in sys.argv the first element (sys.argv[0]) is the script 
 name, and arguments start at sys.argv[1].

Oopsie - you are quite correct.  Good catch.

-- 
Brooks's Law: Adding manpower to a late software project makes it later.

Cole Tuininga
Lead Developer
Code Energy, Inc
[EMAIL PROTECTED]
PGP Key ID: 0x43E5755D


___
gnhlug-discuss mailing list
[EMAIL PROTECTED]
http://mail.gnhlug.org/mailman/listinfo/gnhlug-discuss


Re: Python help

2004-02-05 Thread Derek Martin
On Thu, Feb 05, 2004 at 10:47:56AM -0500, Paul Lussier wrote:
 Obviously a quite rudimentary script, which at this point does nothing
 more than re-create the /etc/group file in sorted order and removes
 the passwd field.
 
 I'd like to see/hear others ideas on how to write this same script.
 I'm most interested in improvements or commentary on why what I did
 is either right, wrong, interesting, stupid, etc.
 
 I'm not overly interesting in shell, perl, tcl, or other language solutions

Then, how about a python script to feed the group file to awk to get
rid of the password field, then pipe the results to sort?  Granted,
this doesn't go a long way to teaching you python, but it does save a
whole lot of typing...  If you don't already know how to do that in
python, it might still be a worthwhile exercise, too.  The resulting
script, I would imagine, would probably be less than 5 lines, and
perhaps as few as 1.  Though, since I don't know a lick of python, I
can't really say.  :)

-- 
Derek D. Martin
http://www.pizzashack.org/
GPG Key ID: 0xDFBEAD02
-=-=-=-=-
This message is posted from an invalid address.
Replying to it will result in undeliverable mail.
Sorry for the inconvenience.  Thank the spammers.



pgp0.pgp
Description: PGP signature


Re: Python help

2004-02-05 Thread Cole Tuininga

First of all, welcome to python!  8)  I do a fair amount of python
coding and am always happy to help out if I can.  

Quick question - what version of python are you running?

 #!/sw/bin/python
 
 import os
 import sys
 
 class gr_struct: # I found this in the docs and it seems
   pass   # to work rather well.

Keep in mind that instantiation of objects is one of python's slower
operations.  If speed matters, you'd do much better to use a dictionary.

 gr_hash = {}
 group = gr_struct()
 
 fp=open(sys.argv[1], 'r')
 
 for i in fp:
i=i.strip(\n)
line = i.split(':')
group.name = line[0]  # what I don't quite get is *why* this works
group.gid = line[2]   # but it certainly beats the dealing
  # with nested/anon dictionaries
  # (though I think I like
  # perl's hashes better
 
group.members = line[3].split(',')
gr_hash = {group.name: group}


Why this works is that unless you do some work to prevent it, objects will create 
member variable references on the fly.  You can't do a test against one before you set 
it, so for instance, doing something like:
if group.bob == something:

would throw an exception, unless you explicit define group.bob before
hand.  You're essentially using an instance of an object as a dict,
which again leads me to think you should just use a dict.  8)

Note, the code as I'm reading it right now will not work.  You will end
up with a single entry repeated many times in the output.  The reason
for this is that you are using the same object over and over.  Keep in
mind that python is heavily referential.  When you say gr_hash =
{group.name: group} but not changing the reference to group, each of the
items are going to point to the same object.  

What I *think* you want is to put the group = gr_struct() line within
the loop.

 fp.close()
 skeys = gr_hash.keys()
 string = ''
 for key in skeys:
 members = gr_hash[key].members # why can't I do 
#  gr_hash[key].members.sort()
 members.sort()

The reason you can't do this in place is that sort does not return the
sorted list - it sorts it in place.  I believe the return value for the
sort() method is a None object.  One neat thing about sort is that you
can pass it your own comparison function.  

 for i in members:  # I would expect to be able use
 if string == '':   # i.join() somehow, but that doesn't
string = i  # seem to work
 else:
string += ',' + i
 print key + : + gr_hash[key].gid + : + string

string is not a great name for a variable, IMNSHO.  8)

I believe the join syntax you want is:
member_names = ','.join( members )

-- 
I have one plan for linux.  World Domination.
 -Linus Torvalds

Cole Tuininga
Lead Developer
Code Energy, Inc
[EMAIL PROTECTED]
PGP Key ID: 0x43E5755D


___
gnhlug-discuss mailing list
[EMAIL PROTECTED]
http://mail.gnhlug.org/mailman/listinfo/gnhlug-discuss


Re: Python help

2004-02-05 Thread Paul Lussier

In a message dated: Thu, 05 Feb 2004 11:17:29 EST
Cole Tuininga said:

First of all, welcome to python!  8)  I do a fair amount of python
coding and am always happy to help out if I can.  

Thanks, I've heard so much about it, I figured it couldn't hurt
to add tool to my tool-box  :)

Quick question - what version of python are you running?

2.2 I think.

Keep in mind that instantiation of objects is one of python's slower
operations.  If speed matters, you'd do much better to use a dictionary.

In this case, speed doesn't matter, but that's good to know, as I'll
eventually be doing some web/CGI programming where it may well matter
(is python good for web/CGI ?)

   group.name = line[0]  # what I don't quite get is *why* this works
   group.gid = line[2]   # but it certainly beats the dealing
 # with nested/anon dictionaries
 # (though I think I like
 # perl's hashes better
 
   group.members = line[3].split(',')
   gr_hash = {group.name: group}


Why this works is that unless you do some work to prevent it, objects
will create member variable references on the fly.  You can't do a
test against on e before you set it, so for instance, doing something
like: if group.bob == something:
would throw an exception, unless you explicit define group.bob before
hand.

Ahh, okay. That's good to know.  I can see where I might end up with
an empty gun and foot full lead doing this :)

You're essentially using an instance of an object as a dict,
which again leads me to think you should just use a dict.  8)

Well, my thinking was that it was more a long the lines of a 
'struct' in C, as noted in the python tutorial.

Note, the code as I'm reading it right now will not work.  You will end
up with a single entry repeated many times in the output.  The reason
for this is that you are using the same object over and over.  Keep in
mind that python is heavily referential.  When you say gr_hash =
{group.name: group} but not changing the reference to group, each of the
items are going to point to the same object.  

Ahh, I had assumed that by changing the object member values,
I'd get those.  But I see your point now.  Of course, with my one line
test file, this wasn't an issue :)

What I *think* you want is to put the group = gr_struct() line within
the loop.

I tried that, but it too seemed to exhibit the above described behavior.
(of course I didn't look too closely at it in other than to just run the
script.  At some point when I have more time, I'll play with it in the
debugger).

 members = gr_hash[key].members # why can't I do 
#  gr_hash[key].members.sort()
 members.sort()

The reason you can't do this in place is that sort does not return the
sorted list - it sorts it in place.  I believe the return value for the
sort() method is a None object.  One neat thing about sort is that you
can pass it your own comparison function.  

Hmmm, okay.  That's similar to perl's sort { func } list thingy.

string is not a great name for a variable, IMNSHO.  8)

It's better than 'str' which is what I started with ;)
I know.  I'm just messing around right now, and will clean this all up
a great deal when I figure out what I'm doing.

I believe the join syntax you want is:
member_names = ','.join( members )

Interesting. I didn't know you could do that!

Thanks,

Seeya,
Paul
--
Key fingerprint = 1660 FECC 5D21 D286 F853  E808 BB07 9239 53F1 28EE

It may look like I'm just sitting here doing nothing,
   but I'm really actively waiting for all my problems to go away.

 If you're not having fun, you're not doing it right!

___
gnhlug-discuss mailing list
[EMAIL PROTECTED]
http://mail.gnhlug.org/mailman/listinfo/gnhlug-discuss


Re: Python help

2004-02-05 Thread Cole Tuininga
On Thu, 2004-02-05 at 13:21, Paul Lussier wrote:
 Quick question - what version of python are you running?
 
 2.2 I think.

Fair enough.  My opinion is: so long as you're running something newer
than 2.1.  2.3.x is the latest, but until you get a bit more used to
the language, you probably won't notice much difference.

 In this case, speed doesn't matter, but that's good to know, as I'll
 eventually be doing some web/CGI programming where it may well matter
 (is python good for web/CGI ?)

As a CGI language, it suffers much the same as many interpreted
languages.  The interpreter has to fire up, read in the code (plus
included modules), then process.  Python has one minor advantage over
perl in that the first time you run it, it compiles it to bytecode and
saves that as a file.  Saves a step next time you run it if you haven't
modified the source file.

The other option is that there is an apache foundation project
(mod_python).  It's not quite as mature as mod_perl, but it does have
some pretty cool features.


 Ahh, okay. That's good to know.  I can see where I might end up with
 an empty gun and foot full lead doing this :)

Big time.  8)

 Well, my thinking was that it was more a long the lines of a 
 'struct' in C, as noted in the python tutorial.

Ayup.  Dicts are faster anyway.

 What I *think* you want is to put the group = gr_struct() line within
 I believe the join syntax you want is:
 member_names = ','.join( members )
 
 Interesting. I didn't know you could do that!

Essentially, everything in python is an object, including a hardcoded
string like ','.  Which means that you can call any string methods (such
as join for instance) on them.

-- 
Experience is something you don't get until just after you need it.

Cole Tuininga
Lead Developer
Code Energy, Inc
[EMAIL PROTECTED]
PGP Key ID: 0x43E5755D


___
gnhlug-discuss mailing list
[EMAIL PROTECTED]
http://mail.gnhlug.org/mailman/listinfo/gnhlug-discuss


Re: Python help

2004-02-05 Thread Kevin D. Clark

Cole Tuininga writes:

 As a CGI language, it suffers much the same as many interpreted
 languages.  The interpreter has to fire up, read in the code (plus
 included modules), then process.  Python has one minor advantage over
 perl in that the first time you run it, it compiles it to bytecode and
 saves that as a file.  Saves a step next time you run it if you haven't
 modified the source file.

If this really is an important consideration (and 99.9% of the
time it simply isn't) Perl has a bytecode back end that can be
configured to dump the compiled bytecode out.

(perlcc -B yourfile.pl)

Regards,

--kevin
-- 
Kevin D. Clark (cetaceannetworks.com!kclark)  |   Will hack Perl for
Cetacean Networks, Inc.   |  fine food, good beer,
Portsmouth, N.H. (USA)|   or fun.
alumni.unh.edu!kdc  (GnuPG ID: B280F24E)) |

___
gnhlug-discuss mailing list
[EMAIL PROTECTED]
http://mail.gnhlug.org/mailman/listinfo/gnhlug-discuss


Re: Python help

2004-02-05 Thread Erik Price
Paul Lussier wrote:

I'd like to see/hear others ideas on how to write this same script.
I'm most interested in improvements or commentary on why what I did
is either right, wrong, interesting, stupid, etc.


Below you'll find my stab at it -- it might not be correct, or even run, b/c I haven't 
actually got an /etc/group file to try it out on right now.  There's a couple best 
practices for Python that I've picked up over the past couple of years that I used, 
too:

1. Unless you're literally writing a one-shot throwaway script to do some task that 
you'll probably never do again, try to write your script as a set of functions or 
classes rather than a start-to-finish script.  This is because every Python script can 
be imported into any other Python script as a module (same can be done with Perl using 
a package declaration if I'm not mistaken) by using import myscript where the script 
file is named myscript.py and is located somewhere on your PYTHONPATH (an 
environment variable that tells the Python interpreter where to search for modules to 
import, that by default includes only the current working directory).

2. If you're doing the above, then the way you actually invoke your script is by 
providing a main method (or any other name you prefer).  Then, the only part of your 
script that is *not* located in a function or class definition is the line if 
__name__ == '__main__': main(), which simply invokes the main() function you defined 
if the name of the magic __name__ variable is __main__.  If you are invoking the 
script directly (rather than importing it into another script as a module), then this 
conditional test will prove true, and your main() function will be executed.

3. I read somewhere that a cool trick is setting the arguments of a Python script as 
the default arguments of main() if it is not passed any arguments explicitly.  The 
advantage of this is that, if you're debugging your script in the interactive 
interpreter, you can call the main() function on your script (by importing myscript 
and then calling myscript.main()) and pass it a list of any arbitrary arguments you 
like.  If you pass arguments into main(), they will be used instead of sys.argv (which 
is good because in the interactive interpreter, there are no arguments in sys.argv).

4. I know that a class can be used as a struct in the way you were using, but I don't 
generally use it as such -- the reason I use Python is because it's very 
straightforward and easy to read, and I find that such a use of a Python class is a 
little un-obvious.  In fact, that technique is often used only to show how Python lets 
you dynamically create object attributes at runtime, though I have seen it used in 
real-life Python scripts too.  For my approach, I created a Group class in my 
version of your script, which of course you can now use in any Python script that 
imports your script by referencing it as myscript.Group.  A dict is a more 
straightforward way to use a simple struct-like object, as Cole suggested.  The 
overhead of using a class over a dict is not very significant, though, since Python's 
classes are really just customized dict types behind the scenes.  But you don't need 
to know that.  And because dicts are used so extensively in Python, they are ultra-opt!
imized by the Python developers.  (Also, if performance is a big concern, then you can 
always write some of the code in C and then import it into your Python script as a 
module.)

5. I try to bundle up behavior that is specific to an object into the class that 
defines that object, rather than act upon the object from the outside.  I tried to do 
that here, by providing a toLdifFormat() method on the Group class.  The advantage 
to this is that it simplifies the code that's making use of the Group objects.  Also, 
returning a string from this method rather than printing it makes it more flexible, 
since you can always print it out later but maybe you wanted to write it to a file or 
a database -- in that case, having it in string format is handier.  Likewise, the 
constructor to the Group class lets you set the name, gid, and members manually 
(useful if you're debugging the script from the interactive interpreter, or perhaps if 
using Group from another script), but if you don't, it just sets them to empty 
strings.  In that case you can use the convenience method setValuesFromLine and pass 
in a line read from a /etc/groups file.  Again, this is Group-spec!
ific behavior so it's nice to stuff this code in with the Group class where it can be 
used anywhere the Group class is used.

Anyway, those are just some thoughts on how I implemented your same script in Python.  
In fact, most of my simpler Python scripts end up looking a lot like this -- they 
consist of one or more classes that define the objects in question, and then a simple 
main() function that actually performs the processing using these objects.  Although 
this is a little more verbose than your 

Re: Python help

2004-02-05 Thread Erik Price
Paul Lussier wrote:

I'd like to see/hear others ideas on how to write this same script.
I'm most interested in improvements or commentary on why what I did
is either right, wrong, interesting, stupid, etc.


Below you'll find my stab at it -- it might not be correct, or even run, b/c I haven't 
actually got an /etc/group file to try it out on right now.  There's a couple best 
practices for Python that I've picked up over the past couple of years that I used, 
too:

1. Unless you're literally writing a one-shot throwaway script to do some task that 
you'll probably never do again, try to write your script as a set of functions or 
classes rather than a start-to-finish script.  This is because every Python script can 
be imported into any other Python script as a module (same can be done with Perl using 
a package declaration if I'm not mistaken) by using import myscript where the script 
file is named myscript.py and is located somewhere on your PYTHONPATH (an 
environment variable that tells the Python interpreter where to search for modules to 
import, that by default includes only the current working directory).

2. If you're doing the above, then the way you actually invoke your script is by 
providing a main method (or any other name you prefer).  Then, the only part of your 
script that is *not* located in a function or class definition is the line if 
__name__ == '__main__': main(), which simply invokes the main() function you defined 
if the name of the magic __name__ variable is __main__.  If you are invoking the 
script directly (rather than importing it into another script as a module), then this 
conditional test will prove true, and your main() function will be executed.

3. I read somewhere that a cool trick is setting the arguments of a Python script as 
the default arguments of main() if it is not passed any arguments explicitly.  The 
advantage of this is that, if you're debugging your script in the interactive 
interpreter, you can call the main() function on your script (by importing myscript 
and then calling myscript.main()) and pass it a list of any arbitrary arguments you 
like.  If you pass arguments into main(), they will be used instead of sys.argv (which 
is good because in the interactive interpreter, there are no arguments in sys.argv).

4. I know that a class can be used as a struct in the way you were using, but I don't 
generally use it as such -- the reason I use Python is because it's very 
straightforward and easy to read, and I find that such a use of a Python class is a 
little un-obvious.  In fact, that technique is often used only to show how Python lets 
you dynamically create object attributes at runtime, though I have seen it used in 
real-life Python scripts too.  For my approach, I created a Group class in my 
version of your script, which of course you can now use in any Python script that 
imports your script by referencing it as myscript.Group.  A dict is a more 
straightforward way to use a simple struct-like object, as Cole suggested.  The 
overhead of using a class over a dict is not very significant, though, since Python's 
classes are really just customized dict types behind the scenes.  But you don't need 
to know that.  And because dicts are used so extensively in Python, they are ultra-opt!
imized by the Python developers.  (Also, if performance is a big concern, then you can 
always write some of the code in C and then import it into your Python script as a 
module.)

5. I try to bundle up behavior that is specific to an object into the class that 
defines that object, rather than act upon the object from the outside.  I tried to do 
that here, by providing a toLdifFormat() method on the Group class.  The advantage 
to this is that it simplifies the code that's making use of the Group objects.  Also, 
returning a string from this method rather than printing it makes it more flexible, 
since you can always print it out later but maybe you wanted to write it to a file or 
a database -- in that case, having it in string format is handier.  Likewise, the 
constructor to the Group class lets you set the name, gid, and members manually 
(useful if you're debugging the script from the interactive interpreter, or perhaps if 
using Group from another script), but if you don't, it just sets them to empty 
strings.  In that case you can use the convenience method setValuesFromLine and pass 
in a line read from a /etc/groups file.  Again, this is Group-spec!
ific behavior so it's nice to stuff this code in with the Group class where it can be 
used anywhere the Group class is used.

Anyway, those are just some thoughts on how I implemented your same script in Python.  
In fact, most of my simpler Python scripts end up looking a lot like this -- they 
consist of one or more classes that define the objects in question, and then a simple 
main() function that actually performs the processing using these objects.  Although 
this is a little more verbose than your 

Re: Python help

2004-02-05 Thread Erik Price
Paul Lussier wrote:

I'd like to see/hear others ideas on how to write this same script.
I'm most interested in improvements or commentary on why what I did
is either right, wrong, interesting, stupid, etc.


Below you'll find my stab at it -- it might not be correct, or even run, b/c I haven't 
actually got an /etc/group file to try it out on right now.  There's a couple best 
practices for Python that I've picked up over the past couple of years that I used, 
too:

1. Unless you're literally writing a one-shot throwaway script to do some task that 
you'll probably never do again, try to write your script as a set of functions or 
classes rather than a start-to-finish script.  This is because every Python script can 
be imported into any other Python script as a module (same can be done with Perl using 
a package declaration if I'm not mistaken) by using import myscript where the script 
file is named myscript.py and is located somewhere on your PYTHONPATH (an 
environment variable that tells the Python interpreter where to search for modules to 
import, that by default includes only the current working directory).

2. If you're doing the above, then the way you actually invoke your script is by 
providing a main method (or any other name you prefer).  Then, the only part of your 
script that is *not* located in a function or class definition is the line if 
__name__ == '__main__': main(), which simply invokes the main() function you defined 
if the name of the magic __name__ variable is __main__.  If you are invoking the 
script directly (rather than importing it into another script as a module), then this 
conditional test will prove true, and your main() function will be executed.

3. I read somewhere that a cool trick is setting the arguments of a Python script as 
the default arguments of main() if it is not passed any arguments explicitly.  The 
advantage of this is that, if you're debugging your script in the interactive 
interpreter, you can call the main() function on your script (by importing myscript 
and then calling myscript.main()) and pass it a list of any arbitrary arguments you 
like.  If you pass arguments into main(), they will be used instead of sys.argv (which 
is good because in the interactive interpreter, there are no arguments in sys.argv).

4. I know that a class can be used as a struct in the way you were using, but I don't 
generally use it as such -- the reason I use Python is because it's very 
straightforward and easy to read, and I find that such a use of a Python class is a 
little un-obvious.  In fact, that technique is often used only to show how Python lets 
you dynamically create object attributes at runtime, though I have seen it used in 
real-life Python scripts too.  For my approach, I created a Group class in my 
version of your script, which of course you can now use in any Python script that 
imports your script by referencing it as myscript.Group.  A dict is a more 
straightforward way to use a simple struct-like object, as Cole suggested.  The 
overhead of using a class over a dict is not very significant, though, since Python's 
classes are really just customized dict types behind the scenes.  But you don't need 
to know that.  And because dicts are used so extensively in Python, they are ultra-opt!
imized by the Python developers.  (Also, if performance is a big concern, then you can 
always write some of the code in C and then import it into your Python script as a 
module.)

5. I try to bundle up behavior that is specific to an object into the class that 
defines that object, rather than act upon the object from the outside.  I tried to do 
that here, by providing a toLdifFormat() method on the Group class.  The advantage 
to this is that it simplifies the code that's making use of the Group objects.  Also, 
returning a string from this method rather than printing it makes it more flexible, 
since you can always print it out later but maybe you wanted to write it to a file or 
a database -- in that case, having it in string format is handier.  Likewise, the 
constructor to the Group class lets you set the name, gid, and members manually 
(useful if you're debugging the script from the interactive interpreter, or perhaps if 
using Group from another script), but if you don't, it just sets them to empty 
strings.  In that case you can use the convenience method setValuesFromLine and pass 
in a line read from a /etc/groups file.  Again, this is Group-spec!
ific behavior so it's nice to stuff this code in with the Group class where it can be 
used anywhere the Group class is used.

Anyway, those are just some thoughts on how I implemented your same script in Python.  
In fact, most of my simpler Python scripts end up looking a lot like this -- they 
consist of one or more classes that define the objects in question, and then a simple 
main() function that actually performs the processing using these objects.  Although 
this is a little more verbose than your 

Re: Python help

2004-02-05 Thread Cole Tuininga

First things first - bravo to you Erik for offering up some more general
(and IMHO) quite correct advice on approaching python scripts rather
than giving quickie advice like I did.

That said, there are two things in your post I wanted to respond to.

 A dict is a more straightforward way to use a 
 simple struct-like object, as Cole suggested.  The overhead of using 
 a class over a dict is not very significant, though, since Python's 
 classes are really just customized dict types behind the scenes.  

This may appear to be true for simple situations.  However, take a look
at http://www.bagley.org/~doug/shootout/bench/objinst/  This is
admittedly old data, using python 2.2, but should still give a general
idea.  Python is quite slow for object instantiation with large numbers
of objects.  Far less true for dictionaries.  

But it all depends on what your needs are, of course.

 But you don't need to know that.  And because dicts are used so 
 extensively in Python, they are ultra-opt!
 imized by the Python developers.  

Very true.  Paul - when you get a little more used to all things
pythonic, check out the setdefault and getdefault methods for
dictionaries.  Very slick.

[snip]


 #!/sw/bin/python
 
 import os, sys
 
 
 class Group:


Next point - the following line has a bug:

 def __init__(self, name=, gid=, members=[]):

This is a very subtle one.  The point is that in a method definition
within an object, you never want to assign a mutable type (namely, the
empty list) to an argument.  Weird behavior will occur.

Example:

#!/usr/bin/python

class bob:
def __init__( self, list_ref = [] ):
self.list_ref = list_ref

def printListRef( self ):
print str( self.list_ref )


b1 = bob()
b2 = bob()

b1.list_ref.append( data )

print b1:,
b1.printListRef()
print b2:,
b2.printListRef()

# End of script

When this is run, you will see:
./test.py
b1: ['data']
b2: ['data']

Hey, wait a minute?  We only assigned data into b1!  Why did this
happen?  The answer is again due to python's heavy use of references.

When you instantiate an object, you are copying a lot of items from the
class definition - including references to arguments.  

When I do b1 = bob(), I'm getting a reference to that empty list defined
in the __init__ method's signature.  When I do b2 = bob(), I'm getting a
reference to the exact *same* list.  So from then on, any instantiated
object will be sharing that list.

Instead, what you want is something like this:

def __init__(self, name=, gid=, members=None):
self.name = name
self.gid = gid
if members is None:
self.members = []
else:
self.members = members

 self.name = name
 self.gid = gid
 self.members = members
 
 def setValuesFromFileLine(self, line):

Can I recommend changing the following to
record = line.strip().split(:)

 record = line.split(:)
 self.name = record[0]
 self.gid = record[2]
 self.members = record[3].split(,)
 
 def toLdifFormat(self):
 self.members.sort()
 output = ,.join(members)
 return %s:%s:%s % (self.name, self.gid, output)
 
 
 
 def main(args=sys.argv):

One point about the above line - if you're testing from a python prompt,
you'll need to pass your arguments in as a list.  So for instance,
 main( [/etc/group] )

rather than just

 main ( /etc/group )

Otherwise, the next line would generate some rather peculiar behavior.

 f = file(args[1], r)

Also, below, it looks like you started out wanting to use a list, but
switched to a dict:

 groups = []
 
 for line in f:
 g = Group()
 g.setValuesFromFileLine(line)
 groups_dict[g.name] = g
 
 f.close()
 
 for group in groups:
 print group.toLdifFormat()

Instead, to pick a list which seems reasonable appropriate to me:

groups = []

for line in f:
g = Group()
g.setValuesFromFileLine( line )
groups.append( g )

f.close()

for group in groups:
print group.toLdifFormat()

 if __name__ == __main__:
 main()

These items aren't meant as bashing - I know you said you wrote it
without testing.  I'm just trying to clarify.  8)

-- 
... one of the main causes of the fall of the Roman Empire was that,
 lacking zero, they had no way to indicate successful termination of
 their C programs.  --  Robert Firth

Cole Tuininga
Lead Developer
Code Energy, Inc
[EMAIL PROTECTED]
PGP Key ID: 0x43E5755D


___
gnhlug-discuss mailing list
[EMAIL PROTECTED]
http://mail.gnhlug.org/mailman/listinfo/gnhlug-discuss