我在 Python 3(.8) 中创建了一个委托(delegate)包装类,它允许我完全复制基类的 API、委托(delegate)给底层实例,并在必要时交换底层实例.
我仍然没有获得完整的 API 同等性,所以我想我应该分享并寻求帮助。
我知道这是一个奇怪的选择,但我需要支持现有的 API,该 API (a) 非常广泛,并且 (b) 不在我的控制范围内(第 3 方库),同时能够交换底层实例调用者代码不知道。例如:
with MyResource() as r: # MyResource is my class, while an `r` instance is an instance of a class in a 3rd party library.
# r should be wrapped in the delegating instance
r.do_x()
# -- under the hood, call .__exit__ on the base instance of `r`, and regenerate it without the calling code knowing.
r.do_y() # this is already delegated to the new instance of base `r`
这是我迄今为止的代码:
T = TypeVar("T")
class SwappableWrapper(Generic[T]):
def __init__(self, base: T):
self.__base: T = base
for name in [_ for _ in dir(base) if _ not in ["__class__", "__dict__", "__weakref__"]]:
class_attr = SwappableWrapper.__get_class_attr(type(base), name)
if class_attr:
is_property = isinstance(class_attr, property)
is_function = not is_property and callable(getattr(base, name))
if is_function:
setattr(self, name, self.__call_base_instance(name))
elif is_property:
self.__set_property(name)
else: # make even the normal attributes into getter-style delegating properties.
self.__set_property(name)
@staticmethod
def __get_class_attr(clazz, attr_name: str):
if hasattr(clazz, attr_name):
return getattr(clazz, attr_name)
else:
for parent in clazz.__bases__:
attr = SwappableWrapper.__get_class_attr(parent, attr_name)
if attr:
return attr
return None
def __call_base_instance(self, func_name):
def do_call(*args, **kwargs):
return getattr(self.__get_base_instance(), func_name)(*args, **kwargs)
return do_call
def __set_property(self, name):
setattr(self, name, property(fget=lambda: getattr(self.__get_base_instance(), name),
fset=lambda v: setattr(self.__get_base_instance(), name, v),
fdel=lambda: delattr(self.__get_base_instance(), name)))
def __get_base_instance(self) -> T:
return self.__base
def swap_base_instance_(self, new_base: T) -> None:
print(f"Swap old base: {self.__base} New base: {new_base}")
self.__base = new_base
调用代码的打印方式很奇怪 - 它没有调用新创建的委托(delegate)属性,而是只打印 property(...)
。
很乐意提供任何帮助。谢谢!
最佳答案
我刚刚意识到使用 Python 的动态调度可以轻松解决这个问题。对于后代,您可以通过以下方式实现这一目标:
class SwappableWrapper(Generic[T]):
def __init__(self, base: T):
self.__base: T = base
def __getattr__(self, item):
return getattr(self.__base, item)
def swap_base_instance_(self, new_base: T) -> None:
self.__base = new_base
如需更深入的解释,see this SO question .
关于python - 在 Python 3 中创建自动委托(delegate)包装类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72195089/