0

I got stuck when I try to figure out the following codes:

def with_metaclass(meta, base=object):
    print("[2]")
    return meta("NewBase", (base,), {})

class BaseForm(object):
    def __init__(self, fields, prefix=''):
       print(self.__class__)

    def say(self):
        print("BaseForm")


class FormMeta(type):
    def __init__(cls, name, bases, attrs):
        print("[3]: {!r}, {!r}, {!r}, {!r}, {!r}".format(cls, name, type(cls), bases, attrs))
        type.__init__(cls, name, bases, attrs)

    def __call__(cls, *args, **kwargs):
        print("[4]: {!r}, {!r}".format(cls, type(cls)))
        return type.__call__(cls, *args, **kwargs)

print("[1]")
class Form(with_metaclass(FormMeta, BaseForm)):
    print("[5]")
    def __init__(self):
        NewBase.__init__(self)
        print("[6]: {!r}, {!r}".format(self, type(self)))


# confused position
print(Form.__bases__)

# Form is based on NewBase, however, there is no NewBase
print(dir())

here is the code output:

[1]
[2]
[3]: <class '__main__.NewBase'>, 'NewBase', <class '__main__.FormMeta'>, (<class '__main__.BaseForm'>,), {}
[5]
[3]: <class '__main__.Form'>, 'Form', <class '__main__.FormMeta'>, (<class '__main__.NewBase'>,), {'__module__': '__main__', '__qualname__': 'Form', '__init__': <function Form.__init__ at 0x7f6ad4d76f28>}
(<class '__main__.NewBase'>,)
['BaseForm', 'Form', 'FormMeta', '__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'with_metaclass']

Just like what I commented out, Form is base on NewBase, however, there is not a NewBase class in the main module. A class its base class is not accessible, is an error? But interesting, Form can still call the method, which comes from the parent of its parent.

return long
  • 183
  • 2
  • 9

1 Answers1

0

For the sake of the answer, we don't need the FormMeta class at first. Imagine the definition of Form as follows:

class Form(with_metaclass(meta=type, base=BaseForm)):
    # ...

the with_metaclass call just returns meta("NewBase", (base,), {}), which in this case is just type("NewBase", (base,), {}), which creates a new class called NewBase, which is derived from base (BaseForm in this case), with no additional methods. You can read about it at the type documentation.

The FormMeta metaclass in this case does nothing. It inherits type (that's why it is a meta class), and then just passes the data it receives on to type, plus some print statements. So it is essentially the same as above. You can read more about metaclasses here.

RunOrVeith
  • 4,487
  • 4
  • 32
  • 50
  • Maybe I did not make it clear, my question is that `Form` class based on `NewBase` class, but `NewBase` class is not in the module namespace, i.e `dir()`. So, the parent of `Form` class cannot be accessed. But the instance of `Form` can access the method of `BaseForm` (the parent class of `NewBase`). – return long Nov 20 '18 at 13:32
  • If you want it in the global name space, just use `NewForm = with_metaclass(FormMeta)`, and then `class Form(NewForm)`. Or just use `super():__init__` instead of `NewForm.__init__`. If that is not what you mean, I don't understand your problem – RunOrVeith Nov 20 '18 at 13:38