Python style guidelines
MetalOne
jcb at iteris.com
Sat Mar 13 16:28:26 EST 2004
> It's that "resources acquired" part that messes people up. I've
> seen it over and over and over again. Memory leaks. Dangling
> pointers. Unrecoverable file handles. Especially as functions
> that acquire lots of resources evolve over time and someone adds
> code to acquire another resource or detect another error condition
> and then doesn't find all the subsequent exit points. It's less
> of an issue with languages with proper garbage collection, but it
> can be a real nightmare in (e.g.) C or assembler. Unit tests that
> cover all possible resource leaks are difficult to construct
> correctly. C++ partially addresses the problem with RIAA (if
> coders use it properly) and a hodgepodge of "smart" objects that
> do pseudo self-garbage collection.
>
> A single exit point also gives me a fighting chance to add
> something to the logical end of a function, like setting the "I'm
> done" flag or logging the result.
>
> If I know that my function only has one exit point, then it's also
> easier to add "let's see what this function is returning"
> debugging code, because I know exactly where to put it and where
> to look for it later when I want to take it out. In some systems,
> the fact that a given function reaches its (single) exit point is
> extremely valuable information.
>
> OTOH, I'm usually the first one to stand up at a design review and
> declare that some function or some method is too long or too
> complex and should be broken up *before* such problems occur.
>
> And that all said, I agree that a bunch of pre-checks and a quick
> exit, BEFORE DOING ANYTHING ELSE, near the top of a function can
> make the rest of some functions much more clear. Again, I've seen
> it a million times: I'll add one more validation down here, but
> forget to release that memory we just acquired up there.
>
Good points.
With resource acquistion, I was mainly thinking along the lines of
int file_compare(const char *filename1, const char *filename2)
{
FILE *infile1 = fopen(filename1, "r");
FILE *infile2 = fopen(filename2, "r");
if (!infile1 || !infile2)
{
// error
if (infile2)
fclose(infile2);
if (infile1)
fclose(infile1);
return FAILURE;
}
// compare files
return SUCCESS
}
as opposed to
int file_compare(const char *filename1, const char *filename2)
{
int result = SUCCESS;
FILE *infile1 = fopen(filename1, "r");
if (infile1)
{
FILE *infile2 = fopen(filename2, "r");
if (infile2)
{
// compare files
}
else
{
result = FAILURE;
}
}
else
{
result = FAILURE;
}
if (infile2)
fclose(infile2);
if (infile1)
fclose(infile1);
return result;
}
More information about the Python-list
mailing list