metaclasses and static methods

Michele Simionato mis6 at pitt.edu
Sat Dec 14 14:01:52 EST 2002


Gonzalo Rodriguez wrote:
>The same problem happens for example when you want to declare a
static method, you have to
>use something like 
>def mystaticmethod(*args, **kwargs): 
><whatever> mystaticmethod = staticmethod(mystaticmethod) 
>It would be much better if some kind of pseudo keyword would be
introduced, e.g.
>def static mystaticmethod(*args, **kwargs):
> <whatever>
> Unfortunately, as far as I remember, such syntactic sweetening is not scheduled to happen in the next 2.3. 

This remark of Gonzalo motivated me to write a "solution" base on
metaclasses.
My aim with this exercise is to point out that metaclasses are
wonderful but also
quite dangerous, since they allow to change the syntax of the language
in a
somewhat misterious way. One could even argue that they are rather
unpythonic,
since "implicit is worse than explicit". 
As Martin Lowis says, implementing a new "static" keyword requires to 
change the parser and the modules connected with it, which is a little
bit of work :-(. I think this should be done at some moment in the 
future, since I really would like to have inside classes a notation
like

  def static square(x): # example [1]
     return x*x

instead of the horrible

  def square(x): 
     return x*x
  square=staticmethod(square)

Moreover, I would welcome an optional qualifier "generator" used as

  def generator g(*args):
      #something here
      yield result

In general I think having a parse able to recognize a syntax like 
def <qualifier> <identifier> would be very useful. 

For the moment however, this is not available, therefore let me show
how easy
it is to implement something very close to that notation by using
metaclasses.
The impressive thing is that can be done in eight lines.

What I want to do is to implement example [1] using the notation

  def static_square(x):
      return x*x 

In other words, I would like the code
            

  class C(RecognizeStatic):

      def static_square(x): 
	  return x*x
    
      def show(self):
          print self.square
          print "square of 2 =",self.square(2)	


to be interpreted as 

  class C(object):

      def square(x): 
	  return x*x
      square=staticmethod(square)
    
      def show(self):
          print self.square
	  print "square of 2 =",self.square(2)	


The solution is an eight lines helper class RecognizeStatic:

  class RecognizeStatic(object):
      class __metaclass__(type):
          def __init__(cls,name,bases,clsdict):
              from inspect import isfunction
              for key,value in clsdict.items():
                  if isfunction(value) and key.startswith("static_"):
                      value=staticmethod(value)
                      setattr(cls,key[7:],value)
                

If you try that, you will see that it works. The extension to
classmethod
is left as an exercise for the reader :-)
Moreover, one could add the line setattr(cls,key,value) at the end, to
have
self.static_square to be recognized too (for people loving long
explicit
names).

Suppose however, the class RecognizeStatic to be defined in an
external
module, in such a way that the programmer only see the C class source
code;
for she/he the conversion of the ordinary method static_square to the
staticmethod
square would appeas as an act of Black Magic, particularly if she/he
is not
familiar with the concept of metaclasses and do not suspect the
RecognizeStatic
class to call a metaclass. 

My conclusion: I am happy metaclasses are not typically used by the
causal
programmer, because I see illimited ways of obscuring Python code due
to their
misuse. Maybe one should inforce some convention to the names of
classes
with a __metaclass__ hook ? For instance add a MetaMagic suffix and
use
RecognizeStaticMetaMagic to make clear that RecognizeStatic
automagically
invoke a metaclass ?

I leave this for discussion,

                     meta-static-magically-yours,

                                    Michele



More information about the Python-list mailing list