module not callable - why not?

Josiah Carlson jcarlson at uci.edu
Sun Apr 18 18:08:26 EDT 2004


> Look, here is a partial list of the symptoms of the illness of using
> class-and-module-based OOP:
> 
> (a) You need metaclasses. You have special syntax for usage of
> metaclasses: you need to use the __metaclass__ name tag, in specific
> places.

I've never used metaclasses, and don't forsee a need for them in 
development I'll be undertaking any time in the near (or far) future. 
Standard inheritance works for me and a vast majority of users out there.

In various cases, PEP 318 (decorator syntax) seems to alleviate many 
people's needs for metaclasses and the magic behind them.


> (b) Singletons become a "design pattern", since classes usually cannot
> be used as instances directly.

Singletons aren't nearly as prevalent as you seem to believe.  Take a 
peek in the standard library, and you'll find a large body of good code 
that has chosen not to use the "singleton design pattern".  Truth be 
told, I've used singletons before, but only once.


> (c) You have to create staticmethod and/or classmethod to make a class
> functional.

Please express what you mean by "functional".  I believe you mean...

class blah:
     def __call__(cls):
         print cls
     __call__ = classmethod(call)

blah(object) #should print "<type 'object'>"


In this situation, I believe that a pure module-level function is 
preferable,

def blah(cls):
     print cls


If I have misinterpreted what you mean by 'functional', please correct me.


> (d) Modules can't have properties, nor are callable.

Yeah, I don't see a problem with this.  However, if you feel really 
strongly about it, with a little work, you can create a pseduo-module 
with everything your heart desires.  Of course it'll be ugly, and pretty 
much a hack, but it can be done (without metaclasses).

The real trick is to understand the difference between "is a" and "has 
a" relations.

Modules /are/ namespaces.  They do not have __call__ semantics because 
namespaces shouldn't be called.  Things /inside/ namespaces should be 
called.  Honestly, I'd like to hear an example of a language where 
namespaces are callable

Classes /have/ namespaces.  To handle the encapsulation of data and 
functions into a single passable object, it is convenient for them to 
have namespaces.  The explicit requirement to give a name to the 
instance being implicitly passed (usually 'self'), is to remind users 
"hey, I'm an instance method".  Note that you can call 'self' anything 
you want, it is merely convention, in a similar fashion to using 'cls' 
for classmethods.


> (e) You often need to create three objects: module, class, instance,
> to do the job of one single object. Hence you often see usage of the
> same name for all three of them, weird as it may seem.

I've seen examples of a module and class having the same name, but I 
believe that with the exception of singletons (which are rare in the 
code that I've seen), naming an instance the same as a module or class 
where it came from, is generally frowned upon due to the shadowing of 
the original module/class name.

I also believe that the general consensus for future standard library 
modules is to name classes different from the module that contains them.


> (f) Module inheritance ('import' for containment, 'from ... import'
> for inheritance) differs in syntax with class inheritance ('class
> A(B):')

I wouldn't call import statements inheritance, I would call it loading 
an external module and binding the results to a name.

Just because you can emulate object inheritance with modules, doesn't 
mean it should be done.  In fact, such things are frowned upon in Python.

Take for example the following import statement...
from module import *

The above is frowned upon by Guido and basically everyone else in the 
Python community because it pollutes namespace.

However...
class foo(goo):
    pass

...is perfectly acceptable.  Why?  Because fewer people have issues with 
class inheritance than with module imports.  I don't know why, I just 
try to answer questions like "I'm importing A from B and importing B 
from A, why doesn't it work?" in a way they'll understand.


> (g) Module functions and class methods become two distinct types of
> objects.

Yeah, and it allows functions to exist without being bound to a class or 
an instance.  Ahh, now I know, you're coming from a Java background!

See, in many other languages (C, C++, Lisp, Pascal, SML, Prolog, etc.), 
functions are not required to be bound to classes or class instances. 
Personally, I like the flexibility, and can be found to fill entire 
modules with nothing but functions.  In Java, I would have to make them 
static methods on some object, a fairly foolish (if arbitrary) requirement.


> (h) In module-level functions, you need to use the 'global' statement
> to access module-level attributes. In class (instance) methods, you
> use the 'self' parameter to access instance attributes. (In class'
> classmethods, you use 'cls'.) (Notice that there is a big difference
> between saying "class method" and "classmethod".)

You don't need to use the names 'self' or 'cls' if you don't want to, 
they are just standard convention.  It helps the programmer understand 
that there may be a difference in terms of functionality.

You should also realize that generally, handling module-level attributes 
from within the module, via global, is generally frowned upon.  Again, 
if you feel strongly about it, you are free to destroy the meaning of 
your application by doing something like the following...

class self(object):
     #module-level self

class foo:
     def goo(self): pass
     def bar(self): pass
     bar = classmethod(bar)
     def baz(self): pass
     baz = staticmethod(baz)


Again, the names are different so that there is a signal to the 
programmer that something different may be happening with this 
particular object.


> In prototype-based OOP, you don't have any of these problems. You can
> see that the usage of modules and classes introduces a whole lot of
> repeated/redundant concepts and/or inconsistencies. That's the price
> you pay. It's just an unfortunate historical development that lead us
> to where we are today.

I don't believe that Python is going the way of prototype-based OOP any 
time soon (if ever).  If you are so prototype-fixated (goodness, you 
certainly seem to be), Prothon has prototypes, and I'm sure they will be 
delighted to have you.


  - Josiah



More information about the Python-list mailing list