Apr 21, 2017

[python] metaclass flow

#!/bin/env python


class MetaType(type):

    def __new__(cls, name, bases, attrs):
        print("in meta new")
        print("name: " + name)
        print("bases: " + str(bases))
        print("attrs: " + str(attrs))
        print("klas info: " + str(cls.__class__))
        #  return type(name, bases, attrs)
        #  Above code will lose metatype info,
        #  which De will be built by 'type', not this MetaType.
        return type.__new__(cls, name, bases, attrs)

    def __init__(cls, name, bases, attrs):
        # cls is returned by this def __new__
        print("in meta init")
        print(dir(cls))

    def __call__(cls, *args, **kwargs):
        print("In meta call")
        # will call type instance's __new__ and __init__
        instance = type.__call__(cls, *args, **kwargs)
        return instance


class Base(object):
    __metaclass__ = MetaType

    def __new__(cls):
        print("in base new")
        print(cls.__class__)  # Print MetaType
        return super(Base, cls).__new__(cls)

    def __init__(self, opt):
        print("Base init")


class De(Base):

    def __new__(cls, input):
        print("in De new")
        print(cls.__class__)  # Print MetaType
        #  return super(Base, cls).__new__(cls) # will bypass Base's __new__
        return super(De, cls).__new__(cls)

    def __init__(self, input):
        print("De init")

    def testFunc(self):
        pass


if __name__ == "__main__":
    """
    1. Constructing Base type instance.
    2. Call MetaType __new__, must return with type.__new__, otherwise using
        type(...) with lose the metaclass info.
    3. Call MetaType __init__
    4. Call MetaType __new__, must return with type.__new__, otherwise using
        type(...) with lose the metaclass info.
        This time with 'De's info.
    5. Call MetaType __init__
    6. Since we call De("hi"), now call MetaType's def __call__
        inside it should call type.__call__ to trigger
        calling MetaType's instance's(aka. De) __new__ and __init__
    7. De's __new__ should call super in order to trigger base instance's
        __new__
    8. De's __init__ should call super in order to trigger base instance's
        __init__
    """
    a = De("hi")

-----------
in meta new
name: Base
bases: (<type 'object'>,)
attrs: {'__module__': '__main__', '__metaclass__': <class '__main__.MetaType'>, '__new__': <function __new__ at 0x7fe775497c80>, '__init__': <function __init__ at 0x7fe775497cf8>}
klas info: <type 'type'>
in meta init
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__metaclass__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
in meta new
name: De
bases: (<class '__main__.Base'>,)
attrs: {'__module__': '__main__', 'testFunc': <function testFunc at 0x7fe775497e60>, '__new__': <function __new__ at 0x7fe775497d70>, '__init__': <function __init__ at 0x7fe775497de8>}
klas info: <type 'type'>
in meta init
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__metaclass__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'testFunc']
In meta call
in De new
<class '__main__.MetaType'>
in base new
<class '__main__.MetaType'>
De init

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.