PyWart: Namespace asinitiy and the folly of the global statement

Rick Johnson rantingrickjohnson at gmail.com
Fri Feb 8 05:30:55 CET 2013




Python's use of namespaces is, as we all quite know, "one honking great idea!"; and i must wholeheartedly agree, however, accessing and declaring variables living in python namespaces is a kludge at best, and a malevolent obfuscation at worst!

============================================================
 MODULE LEVEL VARIABLES
============================================================ 

Take module level variables for example. When reading over some source code we really have no idea in which namespace a variable lives. Consider the following:

count = 0
class Blah:
    def meth():
        for x in range(100):
            count = x
     
Where is count living? 

Of course in this simplistic example we can see that count is @ module level, but what about a module with hundreds or even thousands of lines of code, multiple classes, multiple functions, constants out the yin-yang... yes that abomination Tkinter does comes to mind, but i digress... no one can be expected to remember every single variable MUCH LESS remember every variable's scope also, this is madness!

============================================================
 THE GLOBAL FOLLY 
============================================================

The global statement is not only useless but just serves to confuse people who have experience with languages that have "real" global variables -- not that i am promoting the use of "real" global mind you, i find them to be the crutch of inexperienced programmers! 

In the "solution" section below i provide an outline of how to remove the global statement. I just want to rant about it here.

============================================================
 CLASS LEVEL AND INSTANCE LEVEL VARIABLES
============================================================

There are two reasons why i just hate the manner in which python syntax forces me to create and accesses class level and instance level variables:

   1. class level variable creation requires
      no qualification whist access does!
      
   2. self is used confusingly for accessing
      both when self should only be used to
      access instance level variables!
  
Consider this interactive session:

>>> class Foo(object):
	cv = 0 # Class variable.
	def __init__(self):
		Foo.cv += 1
		print Foo.cv	
>>> f1 = Foo()
1
>>> f2 = Foo()
2
>>> f3 = Foo()
3
>>> ...

So python will allow us to create a class level variable WITHOUT qualification however we must qualify the variable to modify it? Okay, okay, we could infer the scope from indention but what about consistency? I would prefer to qualify the variable in both cases! Besides, GvR had the Cojones to force us to write "self" as the first argument to EVERY SINGLE instance method under the justification of "self documenting code" when any sane person could intuit that "self" belongs to the INSTANCE only. Not to mention that Python has visual scoping in the form of forced indentation. GvR needs to answer for this crime against py-manity! But i digress!!!

Oh, but just wait, the real strange stuff is just around the corner. Enter the twilight zone if you dare!

>>> hasattr(Foo, 'cv')
True

Okay, i expected that but...

>>> hasattr(f1, 'cv')
True

How the hell can an INSTANCE have an attribute named "cv" when "cv" is class level? Can you can hear the eery music?, can you see Rod's toothy grin?, I thought so! 

Hell, since we're already falling "head-over-heels" down the rabbit hole we might as enjoy the visuals of a peep through the looking glass of insanity!

>>> class Bar(object):
	cv = 0 # Class variable.
	def __init__(self):
		self.cv += 1
		print self.cv		
>>> b1 = Bar()
1
>>> b2 = Bar()
1
>>> b3 = Bar()
1
>>> ...

Why did Python NOT throw an error? How could "self.cv" possibly execute when there is no instance variable named "cv"? 

============================================================
 SOLUTION
============================================================

It is my strong opinion that all "unqualified" variables must be local to the containing block, func/meth, class, or module. To access any variable outside of the local scope a programmer MUST qualify that variable with the func, class, or module identifiers. Consider the following examples 

# Module: example.py

count = 0

for x in range(100):
    # Increment the module level variable count.
    example.count += 1

def increment():
   # Create a local variable named count.
   count = 0
   # Increment the module level variable named count.
   # No need for stupid global statement or guessing 
   # because our code will be self documenting! (Then 
   # Why the hell am i writing this comment! :-P")
   example.count += 1 
   # Create a new module level variable named foo
   example.foo = "foo"
   # return the local variable count. 
   return count
   
class Foo():
    # Declare a class level variable named "var". Must use
    # class identifier for both declaration and access! 
    Foo.var = 0 
    def __init__(self):
        # Increment the class level variable "var" by one. If
        # we had foolishly tried to access var using "self" we
        # have suffered the NameError.
        Foo.var += 1 
        # If we want to assign variables at the instance level
        # we use self. 
        self.var = "blah" # Instance variable

 *school-bell-rings*
 



More information about the Python-list mailing list