将自己的python程序封装编译成so动态库文件并提供api供他人调用

本文的背景是,我用python写了一份算法的的代码,希望提供给他人使用,但是我又不希望他能看到我的源码,我希望提供给他相应的接口,他可以调用该接口,输入参数,拿到对应的输出参数即可。这样即可以让他使用这份算法,又保护了我们自己的源码。

本文操作的过程是基于Ubuntu24.04完成的。

下面记录一下完整的部署方案

1 创建完整的项目结构

首先需要重构代码结构,使其更适合编译;

完整的项目结构如下所示:

pump_energy_optimizer/
├── pump_optimizer.pyx            # 算法脚本
├── setup.py                     # 编译脚本
├── usage_example.py            # 使用示例
├── requirements.txt             # 依赖列表
└── README.md                   # 说明文档

2 编写核心代码文件

创建一个新的 .pyx 文件(例如 pump_optimizer.pyx)并将原始 Python 代码移入这个文件。其实就是将原来的算法py文件复制一份,后缀改成pyx

 
import math
import copy

class PumpEnergyOptimizer:
    def __init__(self, pipe_resistance=1.0, dynamic_head=1.0, 
                 high_level_alarm=7.0, low_level_alarm=1.0):
        """
        初始化水泵能量优化器
        
        Args:
            pipe_resistance: 管阻 (米)
            dynamic_head: 动扬程 (米)
            high_level_alarm: 高液位报警值 (米)
            low_level_alarm: 低液位报警值 (米)
        """
        self.last_level = None
        self.high_level_alarm = high_level_alarm
        self.low_level_alarm = low_level_alarm
        self.pipe_resistance = pipe_resistance
        self.dynamic_head = dynamic_head
        
        # 标准水泵数据
        self.standard_pump_data = {
            14: {
                'freq': [50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37],
                'flow': [987, 917, 846, 776, 705, 635, 573, 515, 461, 406, 350, 298, 240, 170],
                'power': [58, 55, 52, 48, 45, 42, 40, 37, 34, 31, 29, 27, 23, 21]
            },
            13: {
                'freq': [50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35],
                'flow': [1075, 1009, 940, 870, 799, 727, 657, 590, 530, 473, 420, 360, 310, 255, 190, 100],
                'power': [58, 55, 52, 48, 45, 42, 40, 37, 34, 31, 29, 27, 23, 21, 19, 18]
            },
            12: {
                'freq': [50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34],
                'flow': [1154, 1093, 1030, 962, 894, 823, 752, 680, 610, 550, 487, 434, 380, 325, 268, 210, 140],
                'power': [58, 55, 52, 48, 45, 42, 40, 37, 34, 31, 29, 27, 23, 21, 19, 18, 16]
            },
            11: {
                'freq': [50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33],
                'flow': [1228, 1171, 1113, 1052, 989, 921, 854, 784, 712, 641, 572, 508, 450, 397, 340, 285, 230, 170],
                'power': [58, 55, 52, 48, 45, 42, 40, 37, 34, 31, 29, 27, 23, 21, 19, 18, 16, 15]
            },
            10: {
                'freq': [50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32],
                'flow': [1300, 1245, 1189, 1133, 1075, 1015, 952, 886, 818, 746, 676, 605, 535, 473, 415, 360, 310, 256, 195],
                'power': [58, 55, 52, 48, 45, 42, 40, 37, 34, 31, 29, 27, 23, 21, 19, 18, 16, 15, 14]
            },
            9: {
                'freq': [50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31],
                'flow': [1370, 1320, 1264, 1209, 1154, 1098, 1041, 981, 919, 850, 785, 712, 640, 570, 505, 443, 387, 330, 272, 225],
                'power': [58, 55, 52, 48, 45, 42, 40, 37, 34, 31, 29, 27, 23, 21, 19, 18, 16, 15, 14, 13]
            },
            8: {
                'freq': [50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31],
                'flow': [1458, 1400, 1340, 1285, 1230, 1178, 1123, 1067, 1011, 953, 890, 828, 762, 692, 620, 549, 480, 417, 362, 300],
                'power': [58, 55, 52, 48, 45, 42, 40, 37, 34, 31, 29, 27, 23, 21, 19, 18, 16, 15, 14, 13]
            },
            7: {
                'freq': [50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31],
                'flow': [1620, 1537, 1445, 1375, 1320, 1260, 1200, 1152, 1097, 1040, 980, 930, 870, 808, 743, 675, 604, 532, 462, 398],
                'power': [58, 55, 52, 48, 45, 42, 40, 37, 34, 31, 29, 27, 23, 21, 19, 18, 16, 15, 14, 13]
            }
        }
        
        # 当前使用的水泵数据(可能经过调整)
        self.current_pump_data = copy.deepcopy(self.standard_pump_data)
    
    def set_pump_parameters(self, pipe_resistance=None, dynamic_head=None, 
                           high_level_alarm=None, low_level_alarm=None):
        """
        设置水泵参数
        
        Args:
            pipe_resistance: 管阻 (米)
            dynamic_head: 动扬程 (米)
            high_level_alarm: 高液位报警值 (米)
            low_level_alarm: 低液位报警值 (米)
        """
        if pipe_resistance is not None:
            self.pipe_resistance = pipe_resistance
        if dynamic_head is not None:
            self.dynamic_head = dynamic_head
        if high_level_alarm is not None:
            self.high_level_alarm = high_level_alarm
        if low_level_alarm is not None:
            self.low_level_alarm = low_level_alarm
        
        return True
    
    def set_level_alarm(self, high_level_alarm, low_level_alarm):
        """
        设置液位报警值
        
        Args:
            high_level_alarm: 高液位报警值 (米)
            low_level_alarm: 低液位报警值 (米)
        """
        self.high_level_alarm = high_level_alarm
        self.low_level_alarm = low_level_alarm
        return True
    
    def adjust_pump_data(self, head_to_adjust, flow_factor=1.0, power_factor=1.0, freq_factor=1.0):
        """
        调整特定扬程的水泵数据
        
        Args:
            head_to_adjust: 需要调整的扬程值 (7-14)
            flow_factor: 标准流量动态系数 (0-2)
            power_factor: 标准功率动态系数 (0-2)
            freq_factor: 输出频率动态系数 (0-2)
        """
        if head_to_adjust not in self.current_pump_data:
            raise ValueError(f"扬程 {head_to_adjust} 不在数据范围内 (7-14m)")
        
        # 应用调整系数
        data = self.current_pump_data[head_to_adjust]
        
        # 调整流量
        data['flow'] = [flow * flow_factor for flow in data['flow']]
        
        # 调整功率
        data['power'] = [power * power_factor for power in data['power']]
        
        # 调整频率
        data['freq'] = [freq * freq_factor for freq in data['freq']]
        
        return True
    
    def reset_pump_data(self):
        """重置水泵数据为标准数据"""
        self.current_pump_data = copy.deepcopy(self.standard_pump_data)
        return True
    
    def calculate_total_head(self, current_level):
        """计算总扬程"""
        # 总扬程 = 5m + 8m - 液位值 + 动扬程 + 管阻
        h_total = 5 + 8 - current_level + self.dynamic_head + self.pipe_resistance
        return math.ceil(h_total)  # 向上取整
    
    def interpolate_frequency_power(self, target_flow, head):
        """根据目标流量插值计算频率和功率"""
        if head not in self.current_pump_data:
            raise ValueError(f"扬程 {head}m 不在数据范围内")
        
        data = self.current_pump_data[head]
        flow_list = data['flow']
        freq_list = data['freq']
        power_list = data['power']
        
        # 由于流量列表是递减的,需要调整边界检查逻辑
        if target_flow >= flow_list[0]:
            return freq_list[0], power_list[0]
        if target_flow <= flow_list[-1]:
            return freq_list[-1], power_list[-1]
        
        # 查找流量所在区间(注意:流量是递减的)
        for i in range(1, len(flow_list)):
            if target_flow >= flow_list[i]:
                # 线性插值
                flow_high, flow_low = flow_list[i-1], flow_list[i]
                freq_high, freq_low = freq_list[i-1], freq_list[i]
                power_high, power_low = power_list[i-1], power_list[i]
                
                fraction = (target_flow - flow_low) / (flow_high - flow_low)
                freq = freq_low + fraction * (freq_high - freq_low)
                power = power_low + fraction * (power_high - power_low)
                
                return round(freq, 2), round(power, 2)
        
        return freq_list[-1], power_list[-1]
    
    def check_level_alarm(self, current_level):
        """检查液位报警"""
        alarms = []
        if current_level >= self.high_level_alarm:
            alarms.append(f"高液位报警!当前液位: {current_level}m")
        if current_level <= self.low_level_alarm:
            alarms.append(f"低液位报警!当前液位: {current_level}m")
        return alarms
    
    def should_recalculate(self, current_level):
        """判断是否需要重新计算"""
        if self.last_level is None:
            return True
        return True  # 每次都重新计算
    
    def optimize_pump_operation(self, current_level, total_flow):
        """优化水泵运行方案"""
        # 检查液位报警
        alarms = self.check_level_alarm(current_level)
        
        # 检查是否需要重新计算
        if not self.should_recalculate(current_level):
            return {"recalculate": False, "alarms": alarms}
        
        # 计算总扬程
        total_head = self.calculate_total_head(current_level)
        
        if total_head not in self.current_pump_data:
            raise ValueError(f"扬程 {total_head}m 不在数据范围内 (7-14m)")
        
        data = self.current_pump_data[total_head]
        min_flow = min(data['flow'])
        max_flow = max(data['flow'])
        
        best_solution = None
        best_power = float('inf')
        
        # 方案1: 1台变频泵
        if min_flow <= total_flow <= max_flow:
            freq, power = self.interpolate_frequency_power(total_flow, total_head)
            solution = {
                "scheme": "1台变频泵",
                "variable_pumps": 1,
                "fixed_pumps": 0,
                "frequency": freq,
                "total_power": power,
                "flow_per_variable_pump": total_flow,
                "fixed_pump_flow_per_pump": 0
            }
            if power < best_power:
                best_solution = solution
                best_power = power
        
        # 方案2: 2台变频泵
        flow_per_pump = total_flow / 2
        if min_flow <= flow_per_pump <= max_flow:
            freq, single_power = self.interpolate_frequency_power(flow_per_pump, total_head)
            total_power = 2 * single_power
            solution = {
                "scheme": "2台变频泵",
                "variable_pumps": 2,
                "fixed_pumps": 0,
                "frequency": freq,
                "total_power": total_power,
                "flow_per_variable_pump": flow_per_pump,
                "fixed_pump_flow_per_pump": 0
            }
            if total_power < best_power:
                best_solution = solution
                best_power = total_power
        
        # 方案3: 2台变频泵 + 1台工频泵
        fixed_pump_flow = data['flow'][0]  # 工频泵在最高频率时的流量
        remaining_flow = total_flow - fixed_pump_flow
        if remaining_flow > 0:
            flow_per_variable = remaining_flow / 2
            if min_flow <= flow_per_variable <= max_flow:
                freq, single_power = self.interpolate_frequency_power(flow_per_variable, total_head)
                fixed_pump_power = data['power'][0]  # 工频泵在最高频率时的功率
                total_power = 2 * single_power + fixed_pump_power
                solution = {
                    "scheme": "2台变频泵 + 1台工频泵",
                    "variable_pumps": 2,
                    "fixed_pumps": 1,
                    "frequency": freq,
                    "total_power": total_power,
                    "flow_per_variable_pump": flow_per_variable,
                    "fixed_pump_flow_per_pump": fixed_pump_flow
                }
                if total_power < best_power:
                    best_solution = solution
                    best_power = total_power
        
        # 方案4: 2台变频泵 + 2台工频泵
        fixed_pumps_flow = 2 * data['flow'][0]
        remaining_flow = total_flow - fixed_pumps_flow
        if remaining_flow > 0:
            flow_per_variable = remaining_flow / 2
            if min_flow <= flow_per_variable <= max_flow:
                freq, single_power = self.interpolate_frequency_power(flow_per_variable, total_head)
                fixed_pump_power = data['power'][0]
                total_power = 2 * single_power + 2 * fixed_pump_power
                solution = {
                    "scheme": "2台变频泵 + 2台工频泵",
                    "variable_pumps": 2,
                    "fixed_pumps": 2,
                    "frequency": freq,
                    "total_power": total_power,
                    "flow_per_variable_pump": flow_per_variable,
                    "fixed_pump_flow_per_pump": fixed_pump_flow
                }
                if total_power < best_power:
                    best_solution = solution
                    best_power = total_power
        
        if best_solution is None:
            raise ValueError(f"无法找到合适的泵组配置,总流量 {total_flow} m³/h 超出范围")
        
        # 更新上次计算的液位
        self.last_level = current_level
        
        result = {
            "recalculate": True,
            "total_head": total_head,
            "best_solution": best_solution,
            "alarms": alarms
        }
        
        return result

    def calculate_energy_saving(self, flow, level):
        """
        水泵节能方案计算接口
        
        Args:
            flow: 流量 (m³/h)
            level: 液位 (m)
        
        Returns:
            tuple: (工频泵台数, 变频泵台数, 单台变频泵频率, 单台变频泵流量, 单台工频泵流量, 总功率)
        """
        result = self.optimize_pump_operation(level, flow)
        
        if not result["recalculate"]:
            raise ValueError("液位变化未超过阈值,建议使用上次计算结果")
        
        solution = result["best_solution"]
        
        # 提取所需的输出参数
        fixed_pumps = solution["fixed_pumps"]  # 工频泵台数
        variable_pumps = solution["variable_pumps"]  # 变频泵台数
        frequency = solution["frequency"]  # 单台变频泵频率
        variable_flow = solution["flow_per_variable_pump"]  # 单台变频泵流量
        fixed_flow = solution.get("fixed_pump_flow_per_pump", 0)  # 单台工频泵流量
        total_power = solution["total_power"]  # 总功率
        
        return (fixed_pumps, variable_pumps, frequency, 
                variable_flow, fixed_flow, total_power)


# 厂家调用接口类
class PumpEnergyOptimizerAPI:
    """
    水泵能量优化器API - 供厂家调用
    厂家只需要使用这个类的方法,不需要了解内部实现
    """
    
    def __init__(self):
        self._optimizer = PumpEnergyOptimizer()
    
    def set_pump_parameters(self, pipe_resistance=None, dynamic_head=None, 
                           high_level_alarm=None, low_level_alarm=None):
        """
        设置水泵参数
        
        Args:
            pipe_resistance: 管阻 (米)
            dynamic_head: 动扬程 (米)
            high_level_alarm: 高液位报警值 (米)
            low_level_alarm: 低液位报警值 (米)
        
        Returns:
            bool: 操作是否成功
        """
        try:
            return self._optimizer.set_pump_parameters(
                pipe_resistance, dynamic_head, high_level_alarm, low_level_alarm)
        except Exception as e:
            print(f"设置水泵参数失败: {e}")
            return False
    
    def set_level_alarm(self, high_level_alarm, low_level_alarm):
        """
        设置液位报警值
        
        Args:
            high_level_alarm: 高液位报警值 (米)
            low_level_alarm: 低液位报警值 (米)
        
        Returns:
            bool: 操作是否成功
        """
        try:
            return self._optimizer.set_level_alarm(high_level_alarm, low_level_alarm)
        except Exception as e:
            print(f"设置液位报警值失败: {e}")
            return False
    
    def adjust_pump_data(self, head_to_adjust, flow_factor=1.0, power_factor=1.0, freq_factor=1.0):
        """
        调整水泵数据
        
        Args:
            head_to_adjust: 需要调整的扬程值 (7-14)
            flow_factor: 标准流量动态系数 (0-2)
            power_factor: 标准功率动态系数 (0-2)
            freq_factor: 输出频率动态系数 (0-2)
        
        Returns:
            bool: 操作是否成功
        """
        try:
            return self._optimizer.adjust_pump_data(head_to_adjust, flow_factor, power_factor, freq_factor)
        except Exception as e:
            print(f"调整水泵数据失败: {e}")
            return False
    
    def reset_pump_data(self):
        """
        重置水泵数据为标准数据
        
        Returns:
            bool: 操作是否成功
        """
        try:
            return self._optimizer.reset_pump_data()
        except Exception as e:
            print(f"重置水泵数据失败: {e}")
            return False
    
    def calculate_energy_saving(self, flow, level):
        """
        计算水泵节能方案
        
        Args:
            flow: 流量 (m³/h)
            level: 液位 (m)
        
        Returns:
            tuple: (工频泵台数, 变频泵台数, 单台变频泵频率, 单台变频泵流量, 单台工频泵流量, 总功率)
                  如果计算失败,返回None
        """
        try:
            return self._optimizer.calculate_energy_saving(flow, level)
        except Exception as e:
            print(f"计算节能方案失败: {e}")
            return None


# 简化的厂家调用接口函数
def create_pump_optimizer():
    """
    创建水泵优化器实例
    
    Returns:
        PumpEnergyOptimizerAPI: 水泵优化器API实例
    """
    return PumpEnergyOptimizerAPI()

    

3 创建编译和部署文件

setup.py - 安装脚本:

from setuptools import setup
from Cython.Build import cythonize

setup(
    name="PumpEnergyOptimizer",
    ext_modules=cythonize("pump_optimizer.pyx"),
    zip_safe=False,
)

requirements.txt - 依赖列表:

cython>=0.29.0
setuptools>=45.0

4 编译过程

先在Ubuntu24.04中安装依赖,进入到项目文件夹,打开cmd:

# 创建虚拟环境
python3 -m venv myenv

# 激活虚拟环境
source myenv/bin/activate


pip install -r requirements.txt

# 使用后可以退出虚拟环境
# deactivate

在这里插入图片描述

执行编译:

python3 setup.py build_ext --inplace

在这里插入图片描述
在这里插入图片描述

验证编译结果,写一个python脚本,对so进行验证,其实就是调用其接口

# 引入生成的 pump_optimizer 模块
import pump_optimizer

def main():
    # 创建水泵优化器 API 实例
    optimizer = pump_optimizer.create_pump_optimizer()

    # 1. 设置水泵参数
    print("设置水泵参数:")
    result = optimizer.set_pump_parameters(pipe_resistance=1.2, dynamic_head=1.5,
                                           high_level_alarm=8.0, low_level_alarm=2.0)
    print("设置结果:", result)
    print()

    # 2. 设置液位报警值
    print("设置液位报警值:")
    result = optimizer.set_level_alarm(high_level_alarm=7.0, low_level_alarm=1.0)
    print("设置结果:", result)
    print()

    # 3. 调整水泵数据
    print("调整水泵数据:")
    result = optimizer.adjust_pump_data(head_to_adjust=12, flow_factor=1.1, power_factor=1.2, freq_factor=0.9)
    print("调整结果:", result)
    print()

    # 4. 重置水泵数据
    print("重置水泵数据:")
    result = optimizer.reset_pump_data()
    print("重置结果:", result)
    print()

    # 5. 计算节能方案
    print("计算节能方案:")
    flow = 1500  # 目标流量 (m³/h)
    level = 4    # 当前液位 (m)
    energy_saving_result = optimizer.calculate_energy_saving(flow, level)
    
    print("节能方案计算结果:")
    print(f"工频泵台数: {energy_saving_result[0]}")
    print(f"变频泵台数: {energy_saving_result[1]}")
    print(f"单台变频泵频率: {energy_saving_result[2]} Hz")
    print(f"单台变频泵流量: {energy_saving_result[3]} m³/h")
    print(f"单台工频泵流量: {energy_saving_result[4]} m³/h")
    print(f"总功率: {energy_saving_result[5]} kW")

if __name__ == "__main__":
    main()

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乘凉~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值