Fin*_*inn 32 python python-3.x
我试图在新的样式类中拦截对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
Run Code Online (Sandbox Code Playgroud)
如果我在列表周围使用该代理对象,我会获得非魔术方法的预期行为,但我的包装函数永远不会被魔术方法调用.
>>> 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
Run Code Online (Sandbox Code Playgroud)
如果我不从对象继承(第一行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
Run Code Online (Sandbox Code Playgroud)
如何使用新样式类完成此拦截?
kin*_*all 27
出于性能原因,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)))
Run Code Online (Sandbox Code Playgroud)
用法:
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__
Run Code Online (Sandbox Code Playgroud)
使用__getattr__
和__getattribute__
是类的最后一个资源来响应获取属性.
考虑以下:
>>> class C:
x = 1
def __init__(self):
self.y = 2
def __getattr__(self, attr):
print(attr)
>>> c = C()
>>> c.x
1
>>> c.y
2
>>> c.z
z
Run Code Online (Sandbox Code Playgroud)
__getattr__
只有在没有其他工作时才会调用该方法(它不适用于运算符,您可以在此处阅读).
在您的示例中,__repr__
已经在object
类中定义了许多其他魔术方法 .
有一件事可以做,思考,然后定义那些魔术方法然后调用__getattr__
方法.我和它的答案(链接)检查这个问题以查看一些代码.
归档时间: |
|
查看次数: |
5901 次 |
最近记录: |