Python style: to check or not to check args and data members

Joel Hedlund joel.hedlund at gmail.com
Fri Sep 1 01:12:47 CEST 2006


Hi!

The question of type checking/enforcing has bothered me for a while, and 
since this newsgroup has a wealth of competence subscribed to it, I 
figured this would be a great way of learning from the experts. I feel 
there's a tradeoff between clear, easily readdable and extensible code 
on one side, and safe code providing early errors and useful tracebacks 
on the other. I want both! How do you guys do it? What's the pythonic 
way? Are there any docs that I should read? All pointers and opinions 
are appreciated!

I've also whipped up some examples in order to put the above questions 
in context and for your amusement. :-)

Briefly:

class MyClass(object):
     def __init__(self, int_member = 0):
         self.int_member = int_member
     def process_data(self, data):
         self.int_member += data

The attached files are elaborations on this theme, with increasing 
security and, alas, rigidity and bloat. Even though 
maximum_security_module.py probably will be the safest to use, the 
coding style will bloat the code something awful and will probably make 
maintenance harder (please prove me wrong!). Where should I draw the line?

These are the attached modules:

* nocheck_module.py:
   As the above example, but with docs. No type checking.

* property_module.py
   Type checking of data members using properties.

* methodcheck_module.py
   Type checking of args within methods.

* decorator_module.py
   Type checking of args using method decorators.

* maximum_security_module.py
   Decorator and property type checking.

Let's pretend I'm writing a script, I import one of the above modules 
and then execute the following code

...
my_object = MyClass(data1)
my_object.process_data(data2)

and then let's pretend dataX is of a bad type, say for example str.

nocheck_module.py
=================
Now, if data2 is bad, we get a suboptimal traceback (possibly to 
somewhere deep within the code, and probably with an unrelated error 
message). However, the first point of failure will in fact be included 
in the traceback, so this error should be possible to find with little 
effort. On the other hand, if data1 is bad, the exception will be raised 
somewhere past the point of first failure. The traceback will be 
completely off, and the error message will still be bad. Even worse: if 
both are bad, we won't even get an exception. We will trundle on with 
corrupted data and take no notice. Very clear code, though. Easily 
extensible.

property_module.py
==================
Here we catch that data1 failure. Tracebacks may still be inconcise with 
uninformative error messages, however they will not be as bad as in 
nocheck_module.py. Bloat. +7 or more lines of boilerplate code for each 
additional data member. Quite clear code. Readily extensible.

methodcheck_module.py
=====================
Good, concise tracebacks with exact error messages. Lots of bloat and 
obscured code. Misses errors where data members are changed directly. 
Very hard to read and extend.

decorator_module.py
===================
Good, concise tracebacks with good error messages. Some bloat. Misses 
errors where data members are changed directly. Clear, but somewhat hard 
to extend. Decorators for *all* methods?! This cannot be the purpose of 
python!?

maximum_security_method.py
==========================
Good, concise tracebacks with good error messages. No errors missed (I 
think? :-) . Bloat. Lots of decorators and boilerplate property code all 
over the place (thankfully not within functional code, though). Is this 
how it's supposed to be done?


And if you've read all the way down here I thank you so very much for 
your patience and perseverance. Now I'd like to hear your thoughts on 
this! Where should the line be drawn? Should I just typecheck data from 
unreliable sources (users/other applications) and stick with the 
barebone strategy, or should I go all the way? Did I miss something 
obvious? Should I read some docs? (Which?) Are there performance issues 
to consider?

Thanks again for taking the time.

Cheers!
/Joel Hedlund
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: methodcheck_module.py
URL: <http://mail.python.org/pipermail/python-list/attachments/20060901/85119ccf/attachment.ksh>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: nocheck_module.py
URL: <http://mail.python.org/pipermail/python-list/attachments/20060901/85119ccf/attachment-0001.ksh>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: property_module.py
URL: <http://mail.python.org/pipermail/python-list/attachments/20060901/85119ccf/attachment-0002.ksh>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: decorator_module.py
URL: <http://mail.python.org/pipermail/python-list/attachments/20060901/85119ccf/attachment-0003.ksh>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: maximum_security_module.py
URL: <http://mail.python.org/pipermail/python-list/attachments/20060901/85119ccf/attachment-0004.ksh>


More information about the Python-list mailing list