Python 自省(introspection) : Automatic wrapping of methods

标签 python reflection wrapper inspection

A 类型的对象以及是否有一种方法可以通过编程方式包装类对象?

给定

class A(object):
    def __init__(self):
        ## ..

    def f0(self, a):
        ## ...

    def f1(self, a, b):
        ## ..

我想要另一个包装 A 的类,例如

class B(object):
    def __init__(self):
        self.a = A()

    def f0(self,a):
        try:
            a.f0(a)
        except (Exception),ex:
            ## ...

    def f1(self, a, b):
        try:
            a.f1(a,b)
        except (Exception),ex:
            ## ...

有没有办法通过反射/检查类 A 来创建 B.f0 & B.f1

最佳答案

如果你想通过调用预定义类 A 上的函数来创建类 B,你可以简单地执行 B = wrap_class(A) 带有如下所示的函数 wrap_class:

import copy

def wrap_class(cls):
    'Wraps a class so that exceptions in its methods are caught.'
    # The copy is necessary so that mutable class attributes are not
    # shared between the old class cls and the new class:
    new_cls = copy.deepcopy(cls)
    # vars() is used instead of dir() so that the attributes of base classes
    # are not modified, but one might want to use dir() instead:
    for (attr_name, value) in vars(cls).items():
        if isinstance(value, types.FunctionType):
            setattr(new_cls, attr_name, func_wrapper(value))
    return new_cls

B = wrap_class(A)

正如 Jürgen 所指出的,这会创建一个类的副本;但是,只有在您真的想保留原始类 A 时才需要这样做(如原始问题中所建议的那样)。如果你不关心 A,你可以简单地用一个不执行任何复制的包装器来装饰它,就像这样:

def wrap_class(cls):
    'Wraps a class so that exceptions in its methods are caught.'
    # vars() is used instead of dir() so that the attributes of base classes
    # are not modified, but one might want to use dir() instead:
    for (attr_name, value) in vars(cls).items():
        if isinstance(value, types.FunctionType):
            setattr(cls, attr_name, func_wrapper(value))
    return cls

@wrap_class
class A(object):
    …  # Original A class, with methods that are not wrapped with exception catching

装饰类 A 捕获异常。

元类版本比较重,但原理类似:

import types

def func_wrapper(f):

    'Returns a version of function f that prints an error message if an exception is raised.'

    def wrapped_f(*args, **kwargs):
        try:
            return f(*args, **kwargs)
        except Exception, ex:
            print "Function", f, "raised", ex

    return wrapped_f

class ExceptionCatcher(type):

    'Metaclass that wraps methods with func_wrapper().'

    def __new__(meta, cname, bases, cdict):
        # cdict contains the attributes of class cname:
        for (attr_name, value) in cdict.items():
            if isinstance(value, types.FunctionType):  # Various attribute types can be wrapped differently
                cdict[attr_name] = func_wrapper(value)
        return super(meta, ExceptionCatcher).__new__(meta, cname, bases, cdict)

class B(object):

    __metaclass__ = ExceptionCatcher  # ExceptionCatcher will be used for creating class A

    class_attr = 42  # Will not be wrapped

    def __init__(self):
        pass

    def f0(self, a):
        return a*10

    def f1(self, a, b):
        1/0  # Raises a division by zero exception!

# Test:
b = B()
print b.f0(3.14)
print b.class_attr
print b.f1(2, 3)

这打印:

31.4
42
Function <function f1 at 0x107812d70> raised integer division or modulo by zero
None

你想做的实际上通常是由一个元类完成的,元类是一个类,其实例是一个类:这是一种基于其解析的 Python 代码动态构建 B 类的方法(类 A 的代码,在问题中)。有关这方面的更多信息,请参阅 Chris 的 Wiki(在 part 1parts 2-4 中)对元类的简短描述。

关于Python 自省(introspection) : Automatic wrapping of methods,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7589208/

相关文章:

php - 需要好的 php sql 库

python - 根据列表列表检查列表中组合的存在

c# - 通过 lambda 表达式传递属性名称以读取属性值

java - 反射库在 Android 中返回空列表

reflection - 是否可以使用其中一种方法获取结构的名称?

wrapper - 更改 Woocommerce 中的简码包装器

java - 为什么数字包装类需要提供静态 toString() 方法?

python - 如何选择列表中元组的项目?

python 在 x 轴上旋转值以不重叠

Python 编码问题(可能是从 windows 到 linux 的问题)