我正在try 创建一个对象代理.

因此,我希望有一个全面的 list ,列出我需要实现的所有事情,但我在网上找不到任何可靠的 list .

下面是我从typingbuiltins个模块中获得的97个独特的dunder方法名称.

__abs__
__add__
__aenter__
__aexit__
__aiter__
__and__
__anext__
__await__
__bool__
__bytes__
__call__
__class__
__cmp__
__complex__
__contains__
__delattr__
__delete__
__delitem__
__delslice__
__dir__
__div__
__divmod__
__enter__
__eq__
__exit__
__float__
__floordiv__
__format__
__fspath__
__ge__
__get__
__getattribute__
__getitem__
__getnewargs__
__getslice__
__gt__
__hash__
__iadd__
__iand__
__import__
__imul__
__index__
__init__
__init_subclass__
__instancecheck__
__int__
__invert__
__ior__
__isub__
__iter__
__ixor__
__le__
__len__
__lshift__
__lt__
__mod__
__mul__
__ne__
__neg__
__new__
__next__
__nonzero__
__or__
__pos__
__pow__
__prepare__
__radd__
__rand__
__rdiv__
__rdivmod__
__reduce__
__reduce_ex__
__repr__
__reversed__
__rfloordiv__
__rlshift__
__rmod__
__rmul__
__ror__
__round__
__rpow__
__rrshift__
__rshift__
__rsub__
__rtruediv__
__rxor__
__set__
__setattr__
__setitem__
__setslice__
__sizeof__
__str__
__sub__
__subclasscheck__
__subclasses__
__truediv__
__xor__

推荐答案

要代理一个对象,您只需要实现该对象拥有的dunder方法,因此在最简单的世界中,您不需要执行任何特殊操作来代理它们,而您还没有执行这些操作来代理该对象的其他属性.

然而,问题在于dunder方法是在类上查找的,而不是在对象上查找的,因此,例如,如果实例没有bar属性,Foo().bar将在返回到类之前在实例上查找bar,而Foo() + 5将在类Foo上查找__add__,完全忽略实例.也就是说,如果实例确实有一个名为__add__的实例属性,那么Foo() + 5仍然不会使用该实例属性.

因此,要代理这些dunder方法,它们需要在类级别而不是实例级别进行代理.

from functools import wraps

def proxy_function(name, f):
    @wraps(f)
    def proxied_f(*args, **kwargs):
        print('Proxying function:', name)
        return f(*args, **kwargs)
    return proxied_f

def proxy_object(obj):
    class Proxy:
        def __getattr__(self, name):
            print('Proxying getattr:', name)
            return getattr(obj, name)
        def __hasattr__(self, name):
            print('Proxying hasattr:', name)
            return hasattr(obj, name)
        def __setattr__(self, name, value):
            print('Proxying setattr:', name, '=', repr(value))
            setattr(obj, name, value)
        def __delattr__(self, name):
            print('Proxying delattr:', name)
            delattr(obj, name)
    
    for name, f in obj.__class__.__dict__.items():
        # don't try to overwrite __class__, __getattr__, etc.
        if callable(f) and name not in Proxy.__dict__:
            f = proxy_function(name, f)
            setattr(Proxy, name, f)
    
    return Proxy()

用法:

>>> class Foo:
...     def __add__(self, other):
...         return 'Adding with ' + repr(other)
... 
>>> foo = Foo()
>>> proxy_foo = proxy_object(foo)
>>> foo + 5
'Adding with 5'
>>> proxy_foo + 5
Proxying function: __add__
'Adding with 5'

Python-3.x相关问答推荐

Numpy argmin()以查找最近的元组

在循环中使用Print&S结束参数时出现奇怪的问题

没有这样的命令';角色';-可靠分子

将列表转换为 pandas 数据框,其中列表包含字典

PyQt5 中耦合滑块和拨号小部件.解决结果不一致的问题

try 使用 GEKKO 求解非线性方程组.系统有多种解决方案,但 GEKKO 给出了错误的解决方案.我该如何解决?

Django - ValueError:无法将字符串转换为浮点数:''

如何将列表和字典逐行组合在一起

SqlAlchemy - 从 oracle db 中检索长文本

从 yahoo Finance python 一次下载多只股票

具有 2 个输入的 python 3 map/lambda 方法

如何用pymongo连接远程mongodb

为什么中断比引发异常更快?

Python 3 - Zip 是 pandas 数据框中的迭代器

matplotlib - 模块sip没有属性setapi

如何使用 python http.server 运行 CGI hello world

在动态链接库 Anaconda3\Library\bin\mkl_intel_thread.dll 中找不到序数 242

__iter__ 和 __getitem__ 有什么区别?

在 PyCharm 中配置解释器:请使用不同的 SDK 名称

十六进制字符串到 Python 3.2 中的带符号整数?