gpt4 book ai didi

python - 如何在新样式类中拦截对 python "magic"方法的调用?

转载 作者:IT老高 更新时间:2023-10-28 22:00:48 24 4
gpt4 key购买 nike

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

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

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

>>> 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:)一切都按预期工作:

>>> 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

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

最佳答案

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

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 - 如何在新样式类中拦截对 python "magic"方法的调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9057669/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com