Recursion error in metaclass

Steven D'Aprano steve+comp.lang.python at pearwood.info
Fri Jun 10 23:34:42 EDT 2011


I have a metaclass in Python 3.1:

class MC1(type):
    @staticmethod
    def get_mro(bases):
        print('get_mro called')
        return type('K', bases, {}).__mro__[1:]
    def __new__(cls, name, bases, dict):
        mro = None
        docstring = dict.get('__doc__')
        if docstring == 'ham':
            mro = cls.get_mro(bases)
            dict['__doc__'] = "spam spam spam"
        # Create the class we want, and return it.
        K = super().__new__(cls, name, bases, dict)
        if mro:
            assert K.__mro__ == (K,) + mro
        return K


It seems to work fine:

>>> class A(metaclass=MC1):
...     pass
...
>>> class B(A):
...     'ham'
...
get_mro called
>>> assert B.__doc__ == 'spam spam spam'
>>>


But if I move the call to get_mro outside of the if block, it works fine 
at first, and then blows up with RecursionError:


class MC2(type):
    @staticmethod
    def get_mro(bases):
        print('get_mro called')
        return type('K', bases, {}).__mro__[1:]
    def __new__(cls, name, bases, dict):
        mro = None
        docstring = dict.get('__doc__')
        mro = cls.get_mro(bases)
        if docstring == 'ham':
            dict['__doc__'] = "spam spam spam"
        # Create the class we want, and return it.
        K = super().__new__(cls, name, bases, dict)
        if mro:
            assert K.__mro__ == (K,) + mro
        return K


>>> class C(metaclass=MC2):
...     pass
...
get_mro called
>>>
>>> sys.setrecursionlimit(15)
>>> class D(C):
...     'ham'
...
get_mro called
get_mro called
get_mro called
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 9, in __new__
  File "<stdin>", line 5, in get_mro
  File "<stdin>", line 9, in __new__
  File "<stdin>", line 5, in get_mro
  File "<stdin>", line 9, in __new__
  File "<stdin>", line 4, in get_mro
RuntimeError: maximum recursion depth exceeded while calling a Python 
object



I am utterly perplexed. What's going on here?




-- 
Steven



More information about the Python-list mailing list