Python help

Cole Tuininga colet at code-energy.com
Thu Feb 5 18:14:03 EST 2004


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
colet at code-energy.com
PGP Key ID: 0x43E5755D





More information about the gnhlug-discuss mailing list