python代码加密方案

为何要对代码加密?
python的解释特性是将py编译为独有的二进制编码pyc 文件,然后对pyc中的指令进行解释执行,但是pyc的反编译却非常简单,可直接反编译为源码,当需要将产品发布到外部环境的时候,源码的保护尤为重要。
常见的源码保护手段有如下几种:
  1. 发行.pyc文件  
  2. 代码混淆
  3. 使用py2exe
  4. 使用Cython

一、发行.pyc文件

pyc文件是一种二进制文件,由原生Python文件经过编译后所生成的,py文件编译成pyc文件后加载速度更快而且提高了代码的安全性。pyc的内容与python的版本相关,不同版本编译的pyc文件不一样。

1.1、编译.pyc文件

编译单个py:
python -m compileall xxx.py  # 把单个.py文件编译为字节码文件

pyc会生成在目录下的__pycache__下(前后有双下划线)
生成的文件名命名方式:源文件名.cpython-python版本.pyc
   
编译多个
python -m compileall /path/src/ # 批量生成字节码文件,/path/src/是包含.py文件名的路径
    
将.py文件转化为.pyc文件,实现代码隐藏的需要;.pyc文件的使用与.py文件的使用相同。
# 安装
pip install compileall2

import compileall

# compile_file编译单个文件
compileall.compile_file('main.py')

# compile_dir 函数编译文件夹下的py文件
compileall.compile_dir('Lib/', force=True)

# 使用多处理器编译
compileall.compile_dir('Lib/', workers=2)

1.2、反编译.pyc文件 (.pyc -> .py)

# 安装 uncompyle
pip install uncompyle

# 把 name.pyc 反编译成 name.py
uncompyle6 name.pyc > name.py

反编译多个文件:uncompyle6 -o . *.pyc

1.3、优缺点

优点:
  • 简单方便,提高了一点源码破解门槛
  • pyc 文件的加载速度比 py 文件快
  • 平台兼容性好,.py能在哪里运行,.pyc就能在哪里运行
不足:
  • 解释器兼容性差, .pyc只能在特定版本的解释器上运行
  • 有现成的反编译工具, 破解成本低

二、代码混淆

代码混淆是指在不改变代码逻辑的情况下,对代码结构进行变换,通过一些带有混淆性质的命名、注释等,使代码变得晦涩难懂,从而达到保护代码的作用。

可以这样下手:

  • 移除注释和文档。没有这些说明,在一些关键逻辑上就没那么容易明白了。

  • 改变缩进。完美的缩进看着才舒服,如果缩进忽长忽短,看着也一定闹心。

  • 在 tokens 中间加入一定空格。这就和改变缩进的效果差不多。

  • 重命名函数、类、变量。命名直接影响了可读性,乱七八糟的名字可是阅读理解的一大障碍。

  • 在空白行插入无效代码。这就是障眼法,用无关代码来打乱阅读节奏。

实现方法:

  1. 网站混淆:Oxyry Python Obfuscator - The most reliable python obfuscator in the world, 破解: https://www.cnblogs.com/Eeyhan/p/13154217.html

  2. 使用 pyobfuscate 库进行混淆   (2条消息) Python 源码混淆与加密_pyobfuscate_早起的python的博客-CSDN博客

优点:

  • 简单方便,提高了一点源码破解门槛

  • 兼容性好,只要源码逻辑能够做到兼容,混淆代码亦能

不足:

  • 只能对单个文件混淆,无法做到多个互相有联系的源码文件的联动混淆

  • 代码结构未发生变化,也能获取字节码,破解难度不大

三、打包

类似的还有pyinstaller、Nuitka

  • pyinstaller是通过设置key来对源码进行加密的;
  • nuitka则是将python源码转成C++(这里得到的是二进制的pyd文件,防止了反编译),然后再编译成可执行文件。 
  • py2exe 是一款将 Python 脚本转换为 Windows 平台上的可执行文件的工具。其原理是将源码编译为.pyc文件,加之必要的依赖文件,一起打包成一个可执行文件。

3.1、py2exe打包

使用py2exe进行打包的步骤:

1、编写入口文件。本示例中取名为hello.py:
print('Hello World')
 
2、编写setup.py
from distutils.core import setup
import py2exe
 
setup(console=['hello.py'])
 
3、生成可执行文件
python setup.py py2exe

 

优点:

  • 能够直接打包成 exe,方便分发和执行

  • 破解门槛比 .pyc 更高一些

不足:

  • 兼容性差,只能运行在 Windows 系统上

  • 生成的可执行文件内的布局是明确、公开的,可以找到源码对应的.pyc文件,进而反编译出源码

3.2、pyinstaller打包

1、安装pyinstaller

2、在Terminal下输入:“pyinstaller -F -w *.py” 就可以制作出exe。生成的文件放在同目录dist下。

常用选项​​​

-F(注意大写)是所有库文件打包成一个exe。不加-F参数生成一堆文件,但运行快,压缩后比单个exe文件还小一点点。 加-F参数生成一个exe文件,运行起来慢。
-D:默认选项,创建一个目录,包含exe文件以及大量依赖文件;
-a,–ascii   不包含 Unicode 字符集支持;
-d,–debug   产生 debug 版本的可执行文件;
-i: 后接图标文件名,后缀是.ico,表示用自定义图标生成exe程序
-c:默认选项,使用控制台(就是类似cmd的黑框);(仅对 Windows 有效);
-w: 生成的exe程序不带窗口执行(仅对 Windows 有效);
-o DIR,–out=DIR 指定 spec 文件的生成目录。如果没有指定,则默认使用当前目录来生成 spec 文件;
-p 表示你自己自定义需要加载的类路径,一般情况下用不到;
-n NAME,–name=NAME  指定项目(产生的 spec)名字。如果省略该选项,那么第一个脚本的主文件名将作为 spec 的名字;
-i  选择图标

示例:

book.py:

import webbrowser

url="https://blog.csdn.net/leiwuhen92?type=blog"
print("hello world")
webbrowser.open_new(url)

打包指令:

pyinstaller -F  -i test.ico.ico -w book.py

 

优点:

  • 隐藏源码
  • 方便一用户使用方便,不用再安装什么python啊,第三方包之类的。

缺点:

  • 打包超级慢,启动超级慢

  • 生成的exe比较大

  • 可以反编译  

    Python可执行文件反编译教程(exe转py)_python_脚本之家 (jb51.net)

     (6条消息) Python 反编译:pycdc工具的使用_小嗷犬的博客-CSDN博客

    在线Python pyc文件编译与反编译 (lddgo.net)

 3.3、Nuitka打包

使用python打包工具nuitka进行编译打包 - 知乎 (zhihu.com)

nuitka的作用是将python程序转换成C语言的可执行elf文件。这样在运行时就可以享受到C语言处理过程中的优化,提高速度。经测试,Nuitka打包后的exe比Pyinstaller打包后的exe运行速度提升30%

对于第三方依赖包较多的项目(比如需要import torch,tensorflow,cv2,numpy,pandas,geopy等等)而言,这里最好打包的方式是只将属于自己的代码转成C++,不管这些大型的第三方包!

指令:

python -m nuitka --standalone --show-memory --show-progress --nofollow-imports --plugin-enable=qt-plugins --follow-import-to=utils,src --output-dir=out --windows-icon-from-ico=./logo.ico demo.py

参数:
--standalone:方便移植到其他机器,不用再安装python
--show-memory --show-progress:展示整个安装的进度过程
--nofollow-imports:不编译代码中所有的import,比如keras,numpy之类的。
--plugin-enable=qt-plugins:我这里用到pyqt5来做界面的,这里nuitka有其对应的插件。
--follow-import-to=utils,src:需要编译成C++代码的指定的2个包含源码的文件夹,这里用,来进行分隔。
--output-dir=out:指定输出的结果路径为out。
--windows-icon-from-ico=./logo.ico:指定生成的exe的图标为logo.ico这个图标,这里推荐一个将图片转成ico格式文件的网站(比特虫)。
--windows-disable-console:运行exe取消弹框。这里没有放上去是因为我们还需要调试,可能哪里还有问题之类的。

 四、使用Cython

原理:先用cython将python语言代码转换为c语言代码,然后用c编译器(gcc)生成可执行文件或动态链接库。

4.1、Cpython介绍

Cython是一个编程语言,它通过类似Python的语法来编写C扩展并可以被Python调用,既具备了Python快速开发的特点,又可以让代码运行起来像C一样快,同时还可以方便地调用C library。
Cython是属于python的超集,用于编写python的c扩展语言。
  
pyx文件由 Cython 编译为.c文件,包含 python 扩展模块的代码。.c文件由 C 编译器编译为.so文件(或 Windows 上的.pyd)。
生成的.so文件或pyd文件是D语言(C/C++综合进化版本)生成的二进制文件,理论上很难反编译。

Note: 纯python源码被cython编译后,因为没有使用类型标注等cython语法,故编译后的动态链接库和可执行文件,主要依赖python的运行时,并不依赖C/C++运行时,主要由python解释器执行,多线程GIL的问题同样存在,性能提升有限,但对for循环、大的列表对象遍历性能有明显优化效果。

4.2、安装

# 安装cython
pip3 install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple cython
 
# 安装c编译器(linux需安装python-devel, gcc)
centos: yum install python-devel  gcc
ubuntu: apt-get install build-essential

4.3、使用

先用cython将python语言代码转换为c语言代码,然后用c编译器(gcc)生成可执行文件或动态链接库。
  
通过shell 或 python脚本的方式,将项目启动的入口py编译成可执行文件,将项目的其他.py文件编译成.so(__init__.py除外)

Note: __init__.py文件定义了python的包结构,为了使cython编译后的.so能按照正常路径import,__init__.py不能被编译,故为了保护代码,整个项目的所有__init__.py文件不建议放业务相关代码。

4.3.1、单个文件的编译示例-linux

目录结构如下:
test/
├── test.py
├── main.py

test.py:

def hello():
    print('hello!')

main.py:文件头的#!/usr/bin/python3.8标记是否程序启动文件

#!/usr/bin/python3.8
from test import hello
 
if __name__ == "__main__":
    hello()

4.3.1.1、将启动main.py编译成二进制可执行文件main

 main.py ---> main.c ---> main.o ---> main :

# step1: 将python代码翻译成c代码(main.py -> main.c)
cython -D -3 --directive always_allow_keywords=true --embed main.py
 
# step2: 将c代码编译为目标文件(main.c -> main.o)
gcc -c main.c -fPIC -fwrapv -O2 -Wall -fno-strict-aliasing -I /usr/include/python3.8 -L /usr/bin -lpython3.8 -o main.o
 
# step3: 将目标文件编译为二进制可执行文件(main.o -> main)
gcc main.o -I /usr/include/python3.8 -L /usr/bin -lpython3.8 -o main

 main.py ---> main.c ---> main:

# step1: 将python代码翻译成c代码(main.py -> main.c)
cython -D -3 --directive always_allow_keywords=true --embed main.py
 
# step2: 将c代码编译为二进制可执行文件(main.c -> main)
gcc main.c -I /usr/include/python3.8 -L /usr/bin -lpython3.8 -o main

4.3.1.2、将test.py编译为动态链接库test.so

test.py ---> test.c ---> test.so:

# step1: 将python代码翻译成c代码(test.py -> test.c)
cython -D -3 --directive always_allow_keywords=true test.py
 
# step2: 将c代码编译为linux动态链接库文件(test.c -> test.so)
gcc test.c -shared -pthread -fPIC -fwrapv -O2 -Wall -fno-strict-aliasing -I /usr/include/python3.8 -L /usr/bin -lpython3.8 -o test.so

 cython参数说明:

-D, --no-docstrings, Strip docstrings from the compiled module.
-o, --output-file <filename>   Specify name of generated C file
-2                             Compile based on Python-2 syntax and code semantics.
-3                             Compile based on Python-3 syntax and code semantics.

gcc参数说明:

-shared:
编译动态库时要用到

-pthread:
在Linux中要用到多线程时,需要链接pthread库

-fPIC:
作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),
则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意
位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。

-fwrapv:
它定义了溢出时候编译器的行为——采用二补码的方式进行操作

-O参数
这是一个程序优化参数,一般用-O2就是,用来优化程序用的
-O2:
会尝试更多的寄存器级的优化以及指令级的优化,它会在编译期间占用更多的内存和编译时间。
-O3: 在O2的基础上进行更多的优化

-Wall:
编译时 显示Warning警告,但只会显示编译器认为会出现错误的警告

-fno-strict-aliasing:
“-fstrict-aliasing”表示启用严格别名规则,“-fno-strict-aliasing”表示禁用严格别名规则,当gcc的编译优化参数为“-O2”、“-O3”和“-Os”时,默认会打开“-fstrict-aliasing”。

-I (大写的i):
是用来指定头文件目录
-I /home/hello/include表示将/home/hello/include目录作为第一个寻找头文件的目录,寻找的顺序是:/home/hello/include-->/usr/include-->/usr/local/include

-l:
-l(小写的 L)参数就是用来指定程序要链接的库,-l参数紧接着就是库名,把库文件名的头lib和尾.so去掉就是库名了,例如我们要用libtest.so库库,编译时加上-ltest参数就能用上了

4.3.2、单个文件的编译示例-windows

windows系统使用cython需要确保已安装C/C++编译器且环境变量正确配置,cython能找到编译器。windows系统可使用MSVC(Microsoft Visual C/C++)或者clang编译器。 

将test.py编译为动态链接库test.pyd:
test.py ---> test.c ---> test.pyd:

# step1: 将python代码翻译成c代码(test.py -> test.c)
cython -D -3 --directive always_allow_keywords=true test.py
 
# step2: 将c代码编译为windows动态链接库文件(test.c -> test.pyd)
cythonize -i test.c

最后得到windows下的动态链接库文件test.cp39-win_amd64.pyd,还需要将文件名重命名为test.pyd。

cythonize参数说明:

-b, --build     build extension modules using distutils
-i, --inplace   build extension modules in place using distutils(implies -b),即将编译后的扩展模块直接放在与test.py同级的目录中。

 4.3.3、python编译可执行文件与动态链接库

 https://github.com/leiwuhen92/cython_test  

main.py:主函数入口

#!/usr/bin/python3.8
from test import hello
from compute import compute
 
if __name__ == "__main__":
    hello()
    compute.is_leap_year(1992)

test.py:

def hello():
    print('hello!')

compute/compute.py:

def is_leap_year(year):
    if year%4==0 and year%100!=0 or year%400==0:
        print(year,"是闰年")
    else:
        print(year,"不是闰年")
 
 
if __name__ == "__main__":
    is_leap_year(1992)

setup.py:

import pathlib
import shutil
from subprocess import Popen, PIPE, STDOUT
 
 
# python编译so
def py_to_so(py_to_so_list):
    """
    :param py_to_so_list:  py文件列表,例如[test.py,]
    :return:
    """
    for py_to_so_item in py_to_so_list:
        # 将python代码翻译成c代码
        basename = py_to_so_item[:-3]
        py_to_c = "cython -D -3 --directive always_allow_keywords=true --embed {}".format(py_to_so_item)
        pl = Popen(py_to_c, shell=True, stdout=PIPE, stderr=STDOUT)
        pl.communicate()[0].decode('utf-8', errors='ignore')
 
        # 将c代码编译为linux动态链接库文件(
        c_to_so = "gcc {} -shared -pthread -fPIC -fwrapv -O2 -Wall -fno-strict-aliasing -I /usr/include/python3.8 -L /usr/bin -lpython3.8 -o {}".format(basename + ".c", basename + ".so")
        p2 = Popen(c_to_so, shell=True, stdout=PIPE, stderr=STDOUT)
        p2.communicate()[0].decode('utf-8', errors='ignore')
 
 
def py_to_bin(py_to_bin_list):
    """
    :param py_to_bin_list: py文件列表,例如[main.py,]
    :return:
    """
    for py_to_bin_item in py_to_bin_list:
        basename = py_to_bin_item[:-3]
        # 将python代码翻译成c代码
        py_to_c = "cython -D -3 --directive always_allow_keywords=true --embed {}".format(py_to_bin_item)
        p1 = Popen(py_to_c, shell=True, stdout=PIPE, stderr=STDOUT)
        p1.communicate()[0].decode('utf-8', errors='ignore')
 
        # 将c代码编译为二进制可执行文件
        c_to_bin = "gcc {} -I /usr/include/python3.8 -L /usr/bin -lpython3.8 -o {}".format(basename + ".c", basename)
        p2 = Popen(c_to_bin, shell=True, stdout=PIPE, stderr=STDOUT)
        p2.communicate()[0].decode('utf-8', errors='ignore')
 
 
def clean_build(project):
    """
    清理编译文件夹中的文件
    :param project:
    :return:
    """
    # 清理py文件
    for i in project.glob("**/*.py"):
        if i.name != "__init__.py" or i.name != "setup.py":
            i.unlink()
 
    # 清理c文件
    for j in project.glob("**/*.c"):
        j.unlink()
 
    # 清理__pycache__文件夹
    for k in project.glob("**/__pycache__"):
        shutil.rmtree(k)
 
 
if __name__ == "__main__":
    # 源文件夹
    project_pathlib = pathlib.Path.cwd()
 
    py_to_bin_list = ["main.py"]
    py_to_bin(py_to_bin_list)
 
    py_to_so_list = ["test.py"]
    for py in project_pathlib.glob("**/*.py"):
        if py.name != "__init__.py" and py.name != "setup.py" and py.name != "main.py":
            py_to_so_list.append(str(py))
    py_to_so(py_to_so_list)
 
    clean_build(project_pathlib)

 4.4、优缺点

优点

  • 生成的二进制so(linux)或.pyd(windows)文件难以破解

  • 性能会提升

不足

  • 兼容性稍差,对于不同版本的操作系统,可能需要重新编译

  • 虽然支持大多数Python代码,但如果一旦发现部分代码不支持,完善成本较高

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/30566.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于机器学习的内容推荐算法及其心理学、社会学影响闲谈

基于机器学习的内容推荐算法目前在各类内容类APP中使用的非常普遍。在购物、时尚、新闻咨询、学习等领域&#xff0c;根据用户的喜好&#xff0c;进行较为精准的用户画像与内容推荐。此类算法不但可以较为准确的分析用户的特征&#xff0c;如年龄、性别等&#xff0c;还能通过长…

特征点Features2D类介绍

文章目录 Features2D类介绍1. cv::AgastFeatureDetector2. cv::AKAZE3. cv::BRISK4. cv::FastFeatureDetector5. cv::GFTTDetector6. cv::KAZE7. cv::MSER8. cv::SimpleBlobDetector9. cv::StarDetector10. cv::SIFT11. cv::SURF12. cv::FastFeatureDetector13. cv::AgastFeatu…

最喜爱的编程语言——Python

一、编程语言发展 编程语言&#xff08;programming language&#xff09;可以简单的理解为一种计算机和人都能识别的语言。一种能够让程序员准确地定义计算机所需数据的计算机语言&#xff0c;并精确地定义在不同情况下所应当采取的行动。 编程语言处在不断的发展和变化中&…

【c语言】 -- 详解数组篇

&#x1f4d5;博主介绍&#xff1a;目前大一正在学习c语言&#xff0c;数据结构&#xff0c;计算机网络。 c语言学习&#xff0c;是为了更好的学习其他的编程语言&#xff0c;C语言是母体语言&#xff0c;是人机交互接近底层的桥梁。 本章来学习数据的存储。 让我们开启c语言学…

考虑微网新能源经济消纳的共享储能优化配置(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

C#异步详解

异步编程是指在程序执行过程中&#xff0c;不需要等待某个操作完成&#xff0c;就可以继续执行后续的代码。比如我们开发了一个web页面中有一个上传文件功能&#xff0c;我们上传文件时使用异步操作&#xff0c;就不用等待文件的上传时间&#xff0c;可以先在网页上进行其他操作…

JAVA_HOME变量的详细配置(图文)

用到Java项目的时候&#xff0c;有时候要用到Java_home&#xff0c;这个需要在系统配置中配置一下。如何操作呢&#xff1f;以下为详细的图文步骤。 1&#xff09;打开环境变量的窗口 2&#xff09;打开新建系统变量 3&#xff09;编辑JAVA_HOME 在变量名后输入JAVA_HOME,找到…

Ui自动化测试如何上传文件

前言 实施UI自动化测试的时候&#xff0c;经常会遇见上传文件的操作&#xff0c;那么对于上传文件你知道几种方法呢&#xff1f;今天我们就总结一下几种常用的上传文件的方法&#xff0c;并分析一下每个方法的优点和缺点以及哪种方法效率&#xff0c;稳定性更高 被测HTML代码…

centos直接部署express

centos直接部署express 以下是在CentOS上部署Express应用程序的一般步骤&#xff1a; 1.安装Node.js 在CentOS系统上安装Node.js。可以使用以下命令安装Node.js&#xff1a; sudo yum install nodejs2.安装npm 安装完Node.js后&#xff0c;还需要安装npm&#xff08;Node.…

Python爬虫被封ip解决方案

在使用 Python 程序进行网络爬虫开发时&#xff0c;可能因以下原因导致被封 IP 或封禁爬虫程序&#xff1a; 1、频繁访问网站 爬虫程序可能会在很短的时间内访问网站很多次&#xff0c;从而对目标网站造成较大的负担和压力&#xff0c;这种行为容易引起目标网站的注意并被封禁…

数据结构-队列

数据结构之队列 队列的概念顺序队列循环队列 顺序循环队列的ADT定义1、简单结构体定义2、初始化3、队列的清空4、计算队列的长度5、判断队列是否为空6、插入新的元素7、元素的删除8、遍历输出队列内的所有元素 链队列的ADT定义1、链队列简单结构体定义2、初始化链队列3、判断链…

神秘的临时对象

下面的程序输出什么&#xff1f;为什么&#xff1f; 程序意图&#xff1a; 在 Test() 中以 0 作为参数调用 Test(int i) 将成员变量 mi 的初始值设置为 0 运行结果&#xff1a; 成员变量 mi 的值为随机值 构造函数是一个特殊的函数 是否可以直接调用&#xff1f; 是否可以…

LVS+KeepAlived高可用负载均衡集群

LVSKeepAlived高可用负载均衡集群 1. 高可用群集的相关知识1.普通群集2.高可用群集(HA)3.Keepalived及其工作原理4.Keepalived体系主要模块及其作用5.健康检查方式&#xff08;学名&#xff1a;探针&#xff09; 二、脑裂的形成和解决1.产生脑裂的常见原因及解决方法2.脑裂预防…

谈找工作线上途径

谈找工作 目录概述需求&#xff1a; 设计思路实现思路分析1.51job2.拉勾网 猎聘网站智联招聘网站后记 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better result,wait…

新能源汽车保养vr仿真教学软件为职业培训带来新的思路和方法

电动车电池更换VR虚拟体验是一种利用VR虚拟现实技术实现对电动车电池更换进行模拟仿真演示和实操训练的虚拟仿真实验教学课件&#xff0c;相比传统教学模式&#xff0c;有效提高学生的实践能力和技能水平。 通过VR技术模拟现场&#xff0c;使培训人员可以身临其境滴观摩操作过程…

在 PyTorch 中实现可解释的神经网络模型

动动发财的小手&#xff0c;点个赞吧&#xff01; 目的 深度学习系统缺乏可解释性对建立人类信任构成了重大挑战。这些模型的复杂性使人类几乎不可能理解其决策背后的根本原因。 ❝ 深度学习系统缺乏可解释性阻碍了人类的信任。 ❞ 为了解决这个问题&#xff0c;研究人员一直在…

c++Qt Creator调用 python 完整版 + 解决bug过程

文章目录 创建项目配置python环境导入Python库其他坑点Python.h 头文件报错ModuleNotFoundError: No module named encodings’ 完美解决找不到python文件 成功&#xff01; 文章首发于我的个人博客&#xff1a;欢迎大佬们来逛逛 创建项目 选择创建 qmake 项目&#xff1a; …

【C++】vector的模拟实现

目录 1.vector的结构2.构造函数2.1 无参构造2.2 以迭代器区间作为参数的构造函数2.3 构造n个value值 3.拷贝构造3.1 传统写法3.2 现代写法 4.赋值重载5.迭代器失效问题5.1 reserve和resize5.2 insert 5.3 erase4. 整体代码&#xff08;包含迭代器、析构函数等&#xff09; 1.ve…

springboot实验室管理系统-计算机毕设 附源码86757

springboot实验室管理系统 摘 要 验室管理系统是将实验室的分析仪器通过计算机网络连起来&#xff0c;采用科学的管理思想和先进的数据库技术&#xff0c;实现以实验室为核心的整体环境的全方位管理。它集用户管理&#xff0c;实验室信息管理&#xff0c;实验室预约管理&#x…

Java设计模式——策略模式

1. 策略模式简介 策略模式: 策略模式是一种行为型模式, 它将对象和行为分开, 将行为定义为一个行为接口和具体行为的实现 策略模式最大的特点是行为的变化, 行为之间可以相互替换 每个if判断都可以理解为一个策略. 本模式是的算法可独立于使用它的用户而变化 2. 模式结构 策略…