如何拦截对 python 的“魔术"的调用?新样式类中的方法?

2024-04-21Python开发问题
4

本文介绍了如何拦截对 python 的“魔术"的调用?新样式类中的方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

我正在尝试在新样式类中拦截对 python 双下划线魔术方法的调用.这是一个简单的例子,但它表明了意图:

I'm trying to intercept calls to python's double underscore magic methods in new style classes. This is a trivial example but it show's the intent:

class ShowMeList(object):
    def __init__(self, it):
        self._data = list(it)

    def __getattr__(self, name):
        attr = object.__getattribute__(self._data, name)
        if callable(attr):
            def wrapper(*a, **kw):
                print "before the call"
                result = attr(*a, **kw)
                print "after the call"
                return result
            return wrapper
        return attr

如果我在列表周围使用该代理对象,我会得到非魔法方法的预期行为,但我的包装函数永远不会为魔法方法调用.

If I use that proxy object around list I get the expected behavior for non-magic methods but my wrapper function is never called for magic methods.

>>> l = ShowMeList(range(8))

>>> l #call to __repr__
<__main__.ShowMeList object at 0x9640eac>

>>> l.append(9)
before the call
after the call

>> len(l._data)
9

如果我不从对象继承(第一行 class ShowMeList:)一切都按预期工作:

If I don't inherit from object (first line class ShowMeList:) everything works as expected:

>>> l = ShowMeList(range(8))

>>> l #call to __repr__
before the call
after the call
[0, 1, 2, 3, 4, 5, 6, 7]

>>> l.append(9)
before the call
after the call

>> len(l._data)
9

如何使用新的样式类完成这种拦截?

How do I accomplish this intercept with new style classes?

推荐答案

出于性能原因,Python 总是在类(和父类的)__dict__ 中查找魔术方法,而不使用普通的属性查找机制.一种解决方法是在创建类时使用元类自动为魔术方法添加代理;例如,我使用这种技术来避免为包装类编写样板调用方法.

For performance reasons, Python always looks in the class (and parent classes') __dict__ for magic methods and does not use the normal attribute lookup mechanism. A workaround is to use a metaclass to automatically add proxies for magic methods at the time of class creation; I've used this technique to avoid having to write boilerplate call-through methods for wrapper classes, for example.

class Wrapper(object):
    """Wrapper class that provides proxy access to an instance of some
       internal instance."""

    __wraps__  = None
    __ignore__ = "class mro new init setattr getattr getattribute"

    def __init__(self, obj):
        if self.__wraps__ is None:
            raise TypeError("base class Wrapper may not be instantiated")
        elif isinstance(obj, self.__wraps__):
            self._obj = obj
        else:
            raise ValueError("wrapped object must be of %s" % self.__wraps__)

    # provide proxy access to regular attributes of wrapped object
    def __getattr__(self, name):
        return getattr(self._obj, name)

    # create proxies for wrapped object's double-underscore attributes
    class __metaclass__(type):
        def __init__(cls, name, bases, dct):

            def make_proxy(name):
                def proxy(self, *args):
                    return getattr(self._obj, name)
                return proxy

            type.__init__(cls, name, bases, dct)
            if cls.__wraps__:
                ignore = set("__%s__" % n for n in cls.__ignore__.split())
                for name in dir(cls.__wraps__):
                    if name.startswith("__"):
                        if name not in ignore and name not in dct:
                            setattr(cls, name, property(make_proxy(name)))

用法:

class DictWrapper(Wrapper):
    __wraps__ = dict

wrapped_dict = DictWrapper(dict(a=1, b=2, c=3))

# make sure it worked....
assert "b" in wrapped_dict                        # __contains__
assert wrapped_dict == dict(a=1, b=2, c=3)        # __eq__
assert "'a': 1" in str(wrapped_dict)              # __str__
assert wrapped_dict.__doc__.startswith("dict()")  # __doc__

这篇关于如何拦截对 python 的“魔术"的调用?新样式类中的方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

The End

相关推荐

在xarray中按单个维度的多个坐标分组
groupby multiple coords along a single dimension in xarray(在xarray中按单个维度的多个坐标分组)...
2024-08-22 Python开发问题
15

Pandas中的GROUP BY AND SUM不丢失列
Group by and Sum in Pandas without losing columns(Pandas中的GROUP BY AND SUM不丢失列)...
2024-08-22 Python开发问题
17

pandas 有从特定日期开始的按月分组的方式吗?
Is there a way of group by month in Pandas starting at specific day number?( pandas 有从特定日期开始的按月分组的方式吗?)...
2024-08-22 Python开发问题
10

GROUP BY+新列+基于条件的前一行抓取值
Group by + New Column + Grab value former row based on conditionals(GROUP BY+新列+基于条件的前一行抓取值)...
2024-08-22 Python开发问题
18

PANDA中的Groupby算法和插值算法
Groupby and interpolate in Pandas(PANDA中的Groupby算法和插值算法)...
2024-08-22 Python开发问题
11

PANAS-基于列对行进行分组,并将NaN替换为非空值
Pandas - Group Rows based on a column and replace NaN with non-null values(PANAS-基于列对行进行分组,并将NaN替换为非空值)...
2024-08-22 Python开发问题
10