Python Metaclass : Understanding the 'with_met

2019-02-01 17:38发布

问题:

I want to ask what the with_metaclass() call means in the definition of a class.

E.g.:

class Foo(with_metaclass(Cls1, Cls2)):
  • Is it a special case where a class inherits from a metaclass?
  • Is the new class a metaclass, too?

回答1:

with_metaclass() is a utility class factory function provided by the six library to make it easier to develop code for both Python 2 and 3.

It creates a base class with the specified meta class for you, compatible with the version of Python you are running the code on.

Quoting from the documentation:

Create a new class with base class base and metaclass metaclass. This is designed to be used in class declarations like this:

from six import with_metaclass

class Meta(type):
    pass

class Base(object):
    pass

class MyClass(with_metaclass(Meta, Base)):
    pass

This is needed because the syntax to attach a metaclass changed between Python 2 and 3:

Python 2:

class MyClass(object):
    __metaclass__ = Meta

Python 3:

class MyClass(metaclass=Meta):
    pass

The with_metaclass() function makes use of the fact that metaclasses are a) inherited by subclasses, and b) a metaclass can be used to generate new classes; it effectively creates a new base class by using the metaclass as a factory to generate an empty class:

def with_metaclass(meta, *bases):
    """Create a base class with a metaclass."""
    return meta("NewBase", bases, {})

The NewBase base class's metaclass is meta, both on Python 2 and 3.



回答2:

UPDATE: the six.with_metaclass() function has since been patched with a decorator variant, i.e. @six.add_metaclass(). This update fixes some mro issues related to the base objects. The new decorator would be applied as follows:

import six

@six.add_metaclass(Meta)
class MyClass(Base):
    pass

Here are the patch notes and here is a similar, detailed example and explanation for using a decorator alternative.