如何通过@property装饰器将子类的计算属性值正确传递给父类的属性方法
如何通过@property装饰器将子类的计算属性值正确传递给父类的属性方法
我看了你的代码,问题出在父类Injector的equivalent_geometric_characteristic_injector属性里——你现在是直接通过子类的类名去调用geometric_characteristics_screw_injector和geometric_characteristics_centrifugal_injector,但这两个都是子类的实例属性(用@property装饰的),必须通过具体的实例来访问,而不是类本身。下面给你两种可行的解决方案:
方案一:使用多态(推荐的面向对象实现方式)
这种方式更符合面向对象的设计原则,父类定义一个统一的抽象接口,子类各自实现自己的逻辑,父类不需要判断实例类型,直接调用接口即可,扩展性更好。
修改步骤:
- 在父类
Injector中添加一个抽象的geometric_characteristics属性,强制子类必须实现该方法 - 子类将原有的属性重命名为
geometric_characteristics,实现父类的抽象接口
修改后的完整代码:
import math from dataclasses import dataclass from enum import Enum class AngularValues(Enum): RIGHT_ANGLE = 90 class ConstructiveTypes(Enum): CENTRIFUGAL_INJECTOR = "CENTRIFUGAL" SCREW_INJECTOR = "SCREW" @dataclass(frozen=True, slots=True) class Injector: outer_diameter_injector: float side_wall_thickness_injector: float number_input_tangential_holes: float diameter_input_tangential_holes: float length_input_tangential_holes: float relative_length_twisting_chamber: float diameter_injector_nozzle: float relative_length_injector_nozzle: float angle_nozzle_axis: float mass_flow_rate: float viscosity: float injector_type: str @property def diameter_twisting_chamber_injector(self) -> float: """Возвращает диаметр камеры закручивания центробежной форсунки""" return self.outer_diameter_injector - 2 * self.side_wall_thickness_injector @property def relative_length_tangential_hole(self) -> float: """Возвращает отношение длины входного тангенциального к его диаметру""" return self.length_input_tangential_holes / self.diameter_input_tangential_holes @property def length_twisting_chamber(self) -> float: """Возвращает длину камеры закручивания центробежной форсунки""" return self.relative_length_twisting_chamber * self.diameter_twisting_chamber_injector @property def radius_twisting_chamber_injector(self) -> float: """Возвращает радиус камеры закручивания центробежной форсунки""" return self.diameter_twisting_chamber_injector / 2 @property def radius_input_tangential_holes(self) -> float: """Возвращает радиус входных тангенциальных отверстий""" return self.diameter_input_tangential_holes / 2 @property def radius_tangential_inlet(self) -> float: """Возвращает величину радиуса, на котором расположена ось входного тангенциального отверстия от оси форсунки""" return self.radius_twisting_chamber_injector - self.radius_input_tangential_holes @property def length_injector_nozzle(self) -> float: """Возвращает длину сопла форсунки""" return self.relative_length_injector_nozzle * self.diameter_injector_nozzle @property def radius_injector_nozzle(self) -> float: """Возвращает радиус сопла форсунки""" return self.diameter_injector_nozzle / 2 @property def reynolds_number(self) -> float: """Возвращает число Рейнольдса""" return (4 * self.mass_flow_rate) / (math.pi * self.viscosity * self.diameter_input_tangential_holes * math.sqrt(self.number_input_tangential_holes)) @property def coefficient_friction(self) -> float: """Возвращает коэффициент трения""" return 10 ** ((25.8 / (math.log(self.reynolds_number, 10))**2.58) - 2) @property def geometric_characteristics(self) -> float: """抽象属性:子类必须实现自己的几何特征计算逻辑""" raise NotImplementedError("子类必须实现该属性") @property def equivalent_geometric_characteristic_injector(self) -> float: """Возвращает эквивалентную геометрическую характеристику""" # 直接调用统一的接口,不需要判断类型 geometric_characteristics = self.geometric_characteristics return geometric_characteristics / (1 + self.coefficient_friction / 2 * self.radius_tangential_inlet * (self.radius_tangential_inlet + self.diameter_input_tangential_holes - self.radius_injector_nozzle)) class ScrewInjector(Injector): cross_sectional_area_one_passage_channel: float @property def geometric_characteristics(self) -> float: """Возвращает геометрическую характеристику шнековой форсунки""" return (math.pi * self.radius_tangential_inlet * self.radius_injector_nozzle) / \ (self.number_input_tangential_holes * self.cross_sectional_area_one_passage_channel) class CentrifugalInjector(Injector): @property def geometric_characteristics(self) -> float: """Возвращает геометрическую характеристику центробежной форсунки""" if self.angle_nozzle_axis == AngularValues.RIGHT_ANGLE.value: return (self.radius_tangential_inlet * self.radius_injector_nozzle) / \ (self.number_input_tangential_holes * self.radius_input_tangential_holes**2) else: return (self.radius_tangential_inlet * self.radius_injector_nozzle) / \ (self.number_input_tangential_holes * self.radius_input_tangential_holes**2) * self.angle_nozzle_axis
方案二:直接通过实例访问子类属性(快速修复)
如果不想调整太多代码结构,可以直接在父类的属性方法中通过self访问子类的属性——因为当你创建子类实例时,self就是子类的实例,会拥有子类定义的所有属性。只需要修改equivalent_geometric_characteristic_injector的实现:
@property def equivalent_geometric_characteristic_injector(self) -> float: """Возвращает эквивалентную геометрическую характеристику""" if self.injector_type == ConstructiveTypes.SCREW_INJECTOR.value: geometric_characteristics = self.geometric_characteristics_screw_injector elif self.injector_type == ConstructiveTypes.CENTRIFUGAL_INJECTOR.value: geometric_characteristics = self.geometric_characteristics_centrifugal_injector else: # 可以添加默认处理或者抛出异常 raise ValueError(f"不支持的喷油器类型:{self.injector_type}") return geometric_characteristics / (1 + self.coefficient_friction / 2 * self.radius_tangential_inlet * (self.radius_tangential_inlet + self.diameter_input_tangential_holes - self.radius_injector_nozzle))
两种方案对比:
- 方案一:代码更优雅,耦合度低,后续新增子类时只需要实现
geometric_characteristics属性即可,不需要修改父类代码,符合开闭原则。 - 方案二:改动量极小,适合快速修复现有问题,但耦合度高,如果子类的属性名发生变化,父类也需要同步修改,扩展性较差。
备注:内容来源于stack exchange,提问作者DYNAMIC AEROSPACE
相关产品推荐
相关产品推荐

