Overriding the default type() metaclass before Python runs

后端 未结 2 1602
猫巷女王i
猫巷女王i 2021-02-02 02:05

Here be dragons. You\'ve been warned.

I\'m thinking about creating a new library that will attempt to help write a better test suite.
In order to

2条回答
  •  半阙折子戏
    2021-02-02 02:51

    The following is not advisable, and you'll hit plenty of problems and cornercases implementing your idea, but on Python 3.1 and onwards, you can hook into the custom class creation process by overriding the __build_class__ built-in hook:

    import builtins
    
    
    _orig_build_class = builtins.__build_class__
    
    
    class SomeMockingMeta(type):
        # whatever
    
    
    def my_build_class(func, name, *bases, **kwargs):
        if not any(isinstance(b, type) for b in bases):
            # a 'regular' class, not a metaclass
            if 'metaclass' in kwargs:
                if not isinstance(kwargs['metaclass'], type):
                    # the metaclass is a callable, but not a class
                    orig_meta = kwargs.pop('metaclass')
                    class HookedMeta(SomeMockingMeta):
                        def __new__(meta, name, bases, attrs):
                            return orig_meta(name, bases, attrs)
                    kwargs['metaclass'] = HookedMeta
                else:
                    # There already is a metaclass, insert ours and hope for the best
                    class SubclassedMeta(SomeMockingMeta, kwargs['metaclass']):
                        pass
                    kwargs['metaclass'] = SubclassedMeta
            else:
                kwargs['metaclass'] = SomeMockingMeta
    
        return _orig_build_class(func, name, *bases, **kwargs)
    
    
    builtins.__build_class__ = my_build_class
    

    This is limited to custom classes only, but does give you an all-powerful hook.

    For Python versions before 3.1, you can forget hooking class creation. The C build_class function directly uses the C-type type() value if no metaclass has been defined, it never looks it up from the __builtin__ module, so you cannot override it.

提交回复
热议问题