First practical Python code, comments appreciated
Steve Holden
steve at holdenweb.com
Wed Dec 14 07:25:19 EST 2005
planetthoughtful wrote:
> Hi All,
>
> I've written my first piece of practical Python code (included below),
> and would appreciate some comments. My situation was that I had a
> directory with a number of subdirectories that contained one or more
> zip files in each. Many of the zipfiles had the same filename (which is
> why they had previously been stored in separate directories). I wanted
> to bring all of the zip files (several hundrd in total) down to the
> common parent directory and obviously rename them in the process by
> appending a unique string to each filename.
>
> The code below did the job admirably, but I don't imagine it is
> anywhere near as efficiently written as it could and should be. Note:
> I'm aware there was no need, for example, to wrap the "os.walk(path)"
> statement in a def -- in a couple of places I added extra steps just to
> help familiarize myself with Python syntax.
>
> I'd very much like to see how experienced Python coders would have
> achieved the same task, if any of you can spare a couple of minutes to
> share some knowledge with me.
>
> Many thanks and much warmth,
>
> planetthoughtful
Brave of you. Please note I haven't actually tested the exact format of
these suggestions, so I made have made stupid typos or syntax errors.
>
> import os
> fcount = 0
> path = 'X:\zipfiles'
> def listFiles(path):
> mylist = os.walk(path)
> return mylist
>
> filelist = listFiles(path)
> for s in filelist:
> if len(s[2]) > 0:
You don't really need this "if" - with an empty s the "for" loop on the
next line will simply execute its body zero times, giving the effect you
appear to want without the extra level of logic.
> for f in s[2]:
> pad = str(fcount)
> if len(pad) == 1:
> pad = "00" + pad
> elif len(pad) == 2:
> pad = "0" + pad
>
Here you could take advantage of the string formatting "%" operator and
instead of the "if" statement just say
pad = "%03d" % fcount
>>> ["%03d" % x for x in (1, 3, 10, 30, 100, 300)]
['001', '003', '010', '030', '100', '300']
> (fname, fext) = os.path.splitext(f)
> oldname = f
There isn't really any advantage to this assignment, though I admit it
does show what you are doing a little better. So why not just use
for oldname in s[2]:
to control the loop, and then replace the two statements above with
(fname, fext) = os.path.splitext(oldname)
Note that assignments of one plain name to another are always fast
operations in Pythin, though, so this isn't criminal behaviour - it just
clutters your logic a little having essentially two names for the same
thing.
> newname = fname + "_" + pad + fext
> os.rename(s[0] + "\\" + oldname, path + "\\" + newname)
That form is non-portable. You might argue "I'm never going to run this
program on anything other than Windows", and indeed for throwaway
programs it's often easier to write something non-portable. It's
surprising, though, how often you end up *not* throwing away such
programs, so it can help to write portably from the start. I'd have used
newname = os.path.join(path,
"%s_%s.%s" % (fname, pad, fext))
os.rename(os.path.join(s[0], oldname), newname)
> fcount = fcount + 1
>
Just a few pointers to make the script simpler, but your program is a
very creditable first effort. Let us know what mistakes I made!
regards
Steve
--
Steve Holden +44 150 684 7255 +1 800 494 3119
Holden Web LLC www.holdenweb.com
PyCon TX 2006 www.python.org/pycon/
More information about the Python-list
mailing list