Note to those of you who may be new to Python: I will refer to "print" as a 
function -- just be aware that "print" was a statement before Python3000 was 
introduced.

------------------------------------------------------------
 Introduction:
------------------------------------------------------------
Many languages provide a function, method, or statement by which users can 
write easily to stdout, and Python is no exception with it's own "print" 
function. However, whilst writing to stdout via "print" is slightly less 
verbose than calling the "write" method of "sys.stdout", we don't really gain 
much from this function except a few keystrokes... is this ALL print should be? 
A mere syntactical sugar? For me, i think the "print" function CAN and SHOULD 
be so much more!

------------------------------------------------------------
 Print's Role in Debugging:
------------------------------------------------------------
A print function can be helpful in many ways, and one very important role print 
plays is to inform the programmer of internal states of objects via debug 
messages written to stdout.

Sure, there are fancy debuggers by which internal state and object identity can 
be inspected on the fly, however, "print" is always going to be there no matter 
what libraries or add-on you have available. And let's face it folks, print is 
the most simplistic and intuitive interface you'll ever find for debugging 
purposes. Sure, "print" may not be the most productive for large scale 
debugging, but for the majority of debugging tasks, it's a good fit.

I know some of you will cringe at the idea of using print for debugging, 
however, i will argue that using a debugger can weaken your detective skills. 
If an exception message and trackback are not giving you enough information to 
find the bug, well then, the language OR the code you've written is not worth a 
monkey's toss! 

I've found that many subtle bugs are caused by not limiting the inputs to sane 
values (or types). And with Python's duct typing and implicit casting to 
Boolean, you end up with all sorts of misleading things happening! Maybe you're 
testing for truth values and get a string instead; which screws everything 
up!!! 

Anyhoo, i digress...

------------------------------------------------------------
 Inadequacies of "print" Debugging.
------------------------------------------------------------
In it's current implementation, print is helpful, but in many ways, print is 
lacking it's true potential. Many of the problems that propagate up when using 
print as a debugger focus on the fact that you cannot easily switch the debug 
messages "on" or "off".

Sure, you can comment-out all calls to print, but if you need to see the 
messages again you will be forced to uncomment all the lines again... hey 
that's no fun! 

A "wise programmer" may think he's solved the problem by writing a function 
called "debugprint" that looks like this:

    def debugprint(*args):
        if DEBUG == True:
            print(*args)

However that solution is at best woefully inadequate and at worse a cycle 
burner!

 * Woefully inadequate because: Switching on or off the debug
   messages is only valid in the current module that the
   function was imported. What if you want to kill all
   debugprint messages EVERYWHERE? Do you really want to edit
   "debug = BOOLEAN" in every source file OR do something
   stupid like import debugprint and edit the DEBUG constant
   OR even dumber, edit the debugprint source code? GAWD NO!

 * But even if you are willing to cope with all the "switch-
   on-and-off" nonsense, are you willing to have you code
   slowed by numerous calls to a dead function containing a
   comparison that will always be false?

    ## START INTERACTIVE SESSION ##
    py> from __future__ import print_function
    py> DEBUG = True
    py> def debugprint(*args):
    ...     if not DEBUG:
    ...         return
    ...     print(*args)
    py> debugprint("foo", "bar")
    foo bar
    py> DEBUG = False
    py> code = compile('debugprint("foo", "bar")', '<string>', 'exec')
    py> import dis
    py> dis.disassemble(code)
      1           0 LOAD_NAME                0 (debugprint)
                  3 LOAD_CONST               0 ('foo')
                  6 LOAD_CONST               1 ('bar')
                  9 CALL_FUNCTION            2
                 12 POP_TOP
                 13 LOAD_CONST               2 (None)
                 16 RETURN_VALUE
   ## END INTERACTIVE SESSION ##
   After a few million executions of this superfluous
   comparison your cpu is losing faith in your ability to
   write logical code!

   py> function.call() + false_comparison() == 'cycle burner'
   "YOU BET YOU A$$ IT DOES!!"

------------------------------------------------------------
 Solution.
------------------------------------------------------------
This realization has brought me to the conclusion that Python (and other 
languages) need a "scoped print function". What is a "scoped print function" 
anyway?  Well what i am proposing is that Python include the following "debug 
switches" in the language:

  ------------------------------
   Switch: "__GLOBALDEBUG__"
  ------------------------------
  Global switching allows a programmer to instruct the
  interpreter to IGNORE all print functions or to EVALUATE
  all print functions by assigning a Boolean value of True
  or False respectively to the global switch (Note: global
  switch always defaults to True!).

  Any script that includes the assignment "__GLOBALDEBUG__ =
  False" will disable ALL debug print messages across the
  entire interpreter namespace. In effect, all print
  statements will be treated as comments and ignored by the
  interpreter. No dead functions will be called and no false
  comparisons will be made!

  (Note: __GLOBALDEBUG__ should not be available in any
  local namespace but accessed only form the topmost
  namespace. Something like: __main__.__GLOBALDEBUG__ =
  Boolean

  ------------------------------
   Switch: "__LOCALDEBUG__"
  ------------------------------
  Local switching allows a programmer to turn on (or off)
  debug messages in the module it was declared. Not sure if
  this should be more specific than modules; like classes,
  blocks, or functions??? Of course this declaration will
  be overridden by any global switch.

------------------------------------------------------------
 Concerns:
------------------------------------------------------------
My only concern is that some programmers may be confused why their print calls  
are not working and may not have the capacity to resolve that function named 
"print" is tied to the global and local switches named "__GLOBAL_DEBUG__" and 
"__LOCAL_DEBUG__". To prevent any cognitive dissonance it may be desirable to 
introduce a new function called "debugprint".

*school-bell-rings*
-- 
http://mail.python.org/mailman/listinfo/python-list

Reply via email to