python 元类 type_在Python运行之前覆盖默认的type()元类

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 do that one of the features is a feature that verifies that any object that is being used which isn't the test runner and the system under test has a test double (a mock object, a stub, a fake or a dummy). If the tester wants the live object and thus reduce test isolation it has to specify so explicitly.

The only way I see to do this is to override the builtin type() function which is the default metaclass.

The new default metaclass will check the test double registry dictionary to see if it has been replaced with a test double or if the live object was specified.

Of course this is not possible through Python itself:

>>> TypeError: can't set attributes of built-in/extension type 'type'

Is there a way to intervene with Python's metaclass lookup before the test suite will run (and probably Python)?

Maybe using bytecode manipulation? But how exactly?

解决方案

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.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值