6

Digression Start

I just learnt what metaclasses are in Python. I don't think that the creators of python wanted everyone to use them. I mean name something a metaclass which might not be a class in most cases is enough to divert most people away from this concept!

Digression end

On to my question. I wrote this simple metaclass to add a default doc string to all classes that are created in the module. But it is not working:

def metest(cls,name,bases,dict):
    cls.setattr(cls,'__doc__',"""Default Doc""")
    return type(cls,(),{})

__metaclass__=metest

class test(object):
    pass

print test.__doc__

t=test()

print t.__doc__

Output:

None
None

What am I doing wrong?

ritratt
  • 1,703
  • 4
  • 25
  • 45

5 Answers5

4

I'm not entirely familiar with the global approach you are doing, setting __metaclass__ like that. For all I know, its another valid style.

But I will provide an example of what I am familiar with:

class MeTest(type):
    def __new__(cls,name,bases,dict):
        dict['__doc__'] = """Default Doc"""
        return type.__new__(cls,name,bases,dict)

class Test(object):
    __metaclass__ = MeTest
jdi
  • 90,542
  • 19
  • 167
  • 203
3

I made your example work:

def metest(name, bases, dict):
    print name, bases, dict
    dict['__doc__'] = """New Doc"""
    cls = type(name+"_meta", bases, dict)
    return cls

class Test(object):
    "Old doc"
    __metaclass__ = metest

print Test
print Test.__doc__

t = Test()

print t.__doc__
  1. Make the "meta class" used.
  2. Correct the signature of the "class creation function". The cls will be created by us.
  3. Have an "old" and a "new" docstring in order to distinguish.
glglgl
  • 89,107
  • 13
  • 149
  • 217
2

See this answer: Python metaclass and the object base class

Providing the object base class overrides the module-level metaclass and replaces it with type (the metaclass of object).

In addition, your metaclass is faulty and won't work even if you get it to apply (by setting __metaclass__ inside the class). It should only accept three arguments. You usually see examples that accept four, but that's because the metaclass is usually, guess what, a class, so it accepts an extra "self" argument (which by convention is called cls for metaclasses).

Community
  • 1
  • 1
BrenBarn
  • 242,874
  • 37
  • 412
  • 384
1

Possibly this is what you want. Inheriting from object would make the metaclass type, so you can't do that if you want to use a global metaclass

def metest(name, bases, dct):
    dct['__doc__'] = """Default Doc"""
    return type(name, bases, dct)

__metaclass__=metest

class test:
    pass

print test.__doc__

t=test()

print t.__doc__
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • But shouldn't the metaclass necessarily be a type? Because from what I have understood, all the classes in Python are objects of the `type` class. So if i want to alter all the classes then I need to override the `type` which is what `metaclass` does. So then why should I NOT inherit from `type`? Is it because then it inherits from the non-overridden `type` class? I am confused. :S – ritratt Jun 29 '12 at 13:16
  • @ritratt, `metest` is a function that _returns_ a class that _inherits from type_. The global `__metaclass__=metest` only works for classic classes. Once you inherit from `object` you are setting the metaclass back to `type` unless the class then overrides the metaclass again – John La Rooy Jun 29 '12 at 23:03
1

Your module-level metaclass is overridden, just as stated above by BrenBarn. To fix this, try to code it to return cls instead of setting it as a class instance.

Jaden
  • 265
  • 3
  • 16