Python中替代传引用实现DRY 解决基类方法更新指针不生效问题
核心问题原因
Python 中所有参数传递都是传对象引用,对形参直接赋值(ptr_to_object = new_widget)只是将形参变量重新绑定到新对象,不会修改外部传入的原始变量/实例属性的值,这是语言的核心设计特性。
符合DRY原则的解决方案
方案1:返回值回写(最简洁,无额外依赖)
修改基类方法将处理后的widget返回,子类调用时直接赋值给自身属性,实现逻辑复用的同时完成属性更新。
class BaseWindow: def do_common_task(self, new_widget: QWidget) -> QWidget: # 原有对new_widget的通用处理逻辑保留 return new_widget class WindowA(BaseWindow): ptr_to_obj: QWidget something_widget: Something something_else_widget: SomethingElse def __init__(self) -> None: self.ptr_to_obj = None self.something_widget = None self.something_else_widget = None def switch_obj_value(self) -> None: self.something_widget = Something() self.ptr_to_obj = self.do_common_task(self.something_widget) def switch_another_obj_value(self) -> None: self.something_else_widget = SomethingElse() self.ptr_to_obj = self.do_common_task(self.something_else_widget)
方案2:传属性名+setattr(适合需要修改实例任意属性的场景)
如果需要修改的实例属性不固定,可以将属性名作为字符串传入基类方法,通过setattr直接修改实例的属性值,无需额外包装。
class BaseWindow: def do_common_task(self, attr_name: str, new_widget: QWidget) -> None: # 原有对new_widget的通用处理逻辑保留 setattr(self, attr_name, new_widget) class WindowA(BaseWindow): # 其余属性、初始化代码保持不变 def switch_obj_value(self) -> None: self.something_widget = Something() self.do_common_task("ptr_to_obj", self.something_widget) def switch_another_obj_value(self) -> None: self.something_else_widget = SomethingElse() self.do_common_task("ptr_to_obj", self.something_else_widget)
方案3:可变对象包装(即自定义指针类方案)
如果需要传递类似“指针引用”的效果,可以把要修改的值包装在一个可变容器中(自定义类、列表、字典都可以),修改容器内的元素会同步到外部。
from dataclasses import dataclass from typing import Generic, TypeVar T = TypeVar('T') @dataclass class Ptr(Generic[T]): value: T class BaseWindow: def do_common_task(self, ptr: Ptr[QWidget], new_widget: QWidget) -> None: # 原有对new_widget的通用处理逻辑保留 ptr.value = new_widget class WindowA(BaseWindow): ptr_to_obj: Ptr[QWidget] # 其余属性保持不变 def __init__(self) -> None: self.ptr_to_obj = Ptr(value=None) self.something_widget = None self.something_else_widget = None def switch_obj_value(self) -> None: self.something_widget = Something() self.do_common_task(self.ptr_to_obj, self.something_widget) # 此时self.ptr_to_obj.value已经被更新为新的widget
三种方案通用逻辑全部保留在基类中,完全符合DRY原则,可根据业务场景选择:仅需要更新固定属性优先选方案1;需要动态修改不同实例属性选方案2;确实需要指针传递语义选方案3。
内容的提问来源于stack exchange,提问作者Jimmyt1988
相关产品推荐
相关产品推荐

