19.Python - copy & 浅复制 & 深复制

本文详细介绍了Python中对象赋值、浅拷贝和深拷贝的区别,并通过实例演示了不同拷贝方式对对象的影响。

Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果。


id

什么是id?一个对象的id值在Python解释器里就代表它在内存中的地址

copyPython中是一个模块,所以我们要import引入


>>> import copy

>>> a=[1,2,3]

>>> b=a

>>> id(a)

"""

4382960392

"""

>>> id(b)

"""

4382960392

"""


>>> id(a)==id(b)    #附值后,两者的id相同,为true

True

>>> b[0]=222222  #此时,改变b的第一个值,也会导致a值改变。

>>> print(a,b)

[222222, 2, 3] [222222, 2, 3] #a,b值同时改变




浅拷贝

当使用浅拷贝时,python只是拷贝了最外围的对象本身,内部的元素都只是拷贝了一个引用而已。看代码:

>>> import copy

>>> a=[1,2,3]

>>> c=copy.copy(a)  #拷贝了a的外围对象本身,

>>> id(c)

"""

4383658568

"""

>>> print(id(a)==id(c))  #id 改变 false

"""

False

"""

>>> c[1]=22222   #此时,我去改变c的第二个值时,a不会被改变。

>>> print(a,c)

[1, 2, 3] [1, 22222, 3] #a值不变,c的第二个值变了,这就是copy和‘==’的不同


>>> a=[1,2,[3,4]]  #第三个值为列表[3,4],即内部元素

>>> d=copy.copy(a) #浅拷贝a中的[34]内部元素的引用,非内部元素对象的本身

>>> id(a)==id(d)

False

>>> id(a[2])==id(d[2])

True

>>> a[2][0]=3333  #改变a中内部原属列表中的第一个值

>>> d             #这时d中的列表元素也会被改变

[1, 2, [3333, 4]]





深拷贝

deepcopy对外围和内部元素都进行了拷贝对象本身,而不是对象的引用。

#copy.deepcopy()

>>> e=copy.deepcopy(a) #e为深拷贝了a

>>> a[2][0]=333 #改变a中内部元素列表第一个的值

>>> e

[1, 2, [3333, 4]] #因为时深拷贝,这时e中内部元素[]列表的值不会因为a中的值改变而改变

>>>


[+] Building 3024.6s (18/28) => [internal] load local bake definitions 0.0s => => reading from stdin 1.61kB 0.0s => [celery internal] load build definition from Dockerfile.superset 0.0s => => transferring dockerfile: 4.96kB 0.0s => [celery internal] load metadata for docker.io/apache/superset:latest 0.0s => [superset internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => CACHED [superset 1/24] FROM docker.io/apache/superset:latest@sha256:09735adaae3945c5a8fabbeca31a7954c8c74de195702ba61622aee8604d5c55 0.0s => => resolve docker.io/apache/superset:latest@sha256:09735adaae3945c5a8fabbeca31a7954c8c74de195702ba61622aee8604d5c55 0.0s => [superset-init 2/24] RUN apt-get update && apt-get install -y --no-install-recommends build-essential libssl-dev libffi-dev 2067.2s => [superset 3/24] RUN python -m ensurepip --upgrade || (wget https://bootstrap.pypa.io/get-pip.py -O /tmp/get-pip.py && python /tmp/get-pip.py --user) 2.8s => [superset-init 4/24] RUN python -m pip --version 0.0s => [superset 5/24] RUN python -m pip install --upgrade pip && python -m pip install "gevent>=21.12.0" psutil pymysql flask-appbu 280.1s => [celery 6/24] RUN python -c "import gevent; print(f'✅ Successfully imported gevent {gevent.__version__}')" 0.3s => [superset-init 7/24] RUN mkdir -p /tmp/version 0.2s => [superset 8/24] WORKDIR /tmp/version 0.1s => [superset 9/24] RUN apt-get update && apt-get install -y --no-install-recommends curl jq && rm -rf /var/lib/apt/lists/* 11.7s [+] Building 3024.7s (18/28) => [internal] load local bake definitions 0.0s => => reading from stdin 1.61kB 0.0s => [celery internal] load build definition from Dockerfile.superset 0.0s => => transferring dockerfile: 4.96kB 0.0s => [celery internal] load metadata for docker.io/apache/superset:latest 0.0s => [superset internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => CACHED [superset 1/24] FROM docker.io/apache/superset:latest@sha256:09735adaae3945c5a8fabbeca31a7954c8c74de195702ba61622aee8604d5c55 0.0s => => resolve docker.io/apache/superset:latest@sha256:09735adaae3945c5a8fabbeca31a7954c8c74de195702ba61622aee8604d5c55 0.0s => [superset-init 2/24] RUN apt-get update && apt-get install -y --no-install-recommends build-essential libssl-dev libffi-dev 2067.2s => [superset 3/24] RUN python -m ensurepip --upgrade || (wget https://bootstrap.pypa.io/get-pip.py -O /tmp/get-pip.py && python /tmp/get-pip.py --user) 2.8s => [superset-init 4/24] RUN python -m pip --version 0.0s => [superset 5/24] RUN python -m pip install --upgrade pip && python -m pip install "gevent>=21.12.0" psutil pymysql flask-appbu 280.1s => [celery 6/24] RUN python -c "import gevent; print(f'✅ Successfully imported gevent {gevent.__version__}')" 0.3s => [superset-init 7/24] RUN mkdir -p /tmp/version 0.2s => [superset 8/24] WORKDIR /tmp/version 0.1s => [superset 9/24] RUN apt-get update && apt-get install -y --no-install-recommends curl jq && rm -rf /var/lib/apt/lists/* 11.7s [+] Building 3024.9s (18/28) => [internal] load local bake definitions 0.0s => => reading from stdin 1.61kB 0.0s => [celery internal] load build definition from Dockerfile.superset 0.0s => => transferring dockerfile: 4.96kB 0.0s => [celery internal] load metadata for docker.io/apache/superset:latest 0.0s => [superset internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => CACHED [superset 1/24] FROM docker.io/apache/superset:latest@sha256:09735adaae3945c5a8fabbeca31a7954c8c74de195702ba61622aee8604d5c55 0.0s => => resolve docker.io/apache/superset:latest@sha256:09735adaae3945c5a8fabbeca31a7954c8c74de195702ba61622aee8604d5c55 0.0s => [superset-init 2/24] RUN apt-get update && apt-get install -y --no-install-recommends build-essential libssl-dev libffi-dev 2067.2s => [superset 3/24] RUN python -m ensurepip --upgrade || (wget https://bootstrap.pypa.io/get-pip.py -O /tmp/get-pip.py && python /tmp/get-pip.py --user) 2.8s => [superset-init 4/24] RUN python -m pip --version 0.0s => [superset 5/24] RUN python -m pip install --upgrade pip && python -m pip install "gevent>=21.12.0" psutil pymysql flask-appbu 280.1s => [celery 6/24] RUN python -c "import gevent; print(f'✅ Successfully imported gevent {gevent.__version__}')" 0.3s => [superset-init 7/24] RUN mkdir -p /tmp/version 0.2s => [superset 8/24] WORKDIR /tmp/version 0.1s => [superset 9/24] RUN apt-get update && apt-get install -y --no-install-recommends curl jq && rm -rf /var/lib/apt/lists/* 11.7s [+] Building 3025.0s (18/28) => [internal] load local bake definitions 0.0s => => reading from stdin 1.61kB 0.0s => [celery internal] load build definition from Dockerfile.superset 0.0s => => transferring dockerfile: 4.96kB 0.0s => [celery internal] load metadata for docker.io/apache/superset:latest 0.0s => [superset internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => CACHED [superset 1/24] FROM docker.io/apache/superset:latest@sha256:09735adaae3945c5a8fabbeca31a7954c8c74de195702ba61622aee8604d5c55 0.0s => => resolve docker.io/apache/superset:latest@sha256:09735adaae3945c5a8fabbeca31a7954c8c74de195702ba61622aee8604d5c55 0.0s => [superset-init 2/24] RUN apt-get update && apt-get install -y --no-install-recommends build-essential libssl-dev libffi-dev 2067.2s => [superset 3/24] RUN python -m ensurepip --upgrade || (wget https://bootstrap.pypa.io/get-pip.py -O /tmp/get-pip.py && python /tmp/get-pip.py --user) 2.8s => [superset-init 4/24] RUN python -m pip --version 0.0s => [superset 5/24] RUN python -m pip install --upgrade pip && python -m pip install "gevent>=21.12.0" psutil pymysql flask-appbu 280.1s => [celery 6/24] RUN python -c "import gevent; print(f'✅ Successfully imported gevent {gevent.__version__}')" 0.3s => [superset-init 7/24] RUN mkdir -p /tmp/version 0.2s => [superset 8/24] WORKDIR /tmp/version 0.1s => [superset 9/24] RUN apt-get update && apt-get install -y --no-install-recommends curl jq && rm -rf /var/lib/apt/lists/* 11.7s [+] Building 3025.0s (18/28) => => transferring context: 2B 0.0s => CACHED [superset 1/24] FROM docker.io/apache/superset:latest@sha256:09735adaae3945c5a8fabbeca31a7954c8c 0.0s => => resolve docker.io/apache/superset:latest@sha256:09735adaae3945c5a8fabbeca31a7954c8c74de195702ba61622a 0.0s => [superset-init 2/24] RUN apt-get update && apt-get install -y --no-install-recommends bu 2067.2s => [superset 3/24] RUN python -m ensurepip --upgrade || (wget https://bootstrap.pypa.io/get-pip.py -O 2.8s [+] Building 4365.3s (23/28) => [superset-init 4/24] RUN python -m pip --version 0.0s => [superset 5/24] RUN python -m pip install --upgrade pip && python -m pip install "gevent> 280.1ss => [celery 6/24] RUN python -c "import gevent; print(f'✅ Successfully imported gevent {gevent.__version_ 0.3s => [superset-init 7/24] RUN mkdir -p /tmp/version 0.2s => [superset 8/24] WORKDIR /tmp/version 0.1ss => [superset 9/24] RUN apt-get update && apt-get install -y --no-install-recommends curl jq && rm 11.7ss => [superset-init 10/24] RUN echo '#!/bin/bash\nif [ "${SUPERSET_VERSION}" = "latest" ]; then\n echo "🔍 0.2s => [superset 11/24] RUN chmod +x resolve_version.sh 0.3ss => [superset-init 12/24] RUN ./resolve_version.sh 301.2ss => [superset 13/24] RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | gpg --dearmor -o 1.1ss => [celery 14/24] RUN echo "deb [signed-by=/usr/share/keyrings/nodesource-keyring.gpg] https://deb.nodesour 0.3ss => [superset 15/24] RUN apt-get update && apt-get install -y nodejs npm && rm -rf /var/lib/apt/li 752.1ss => [superset 16/24] RUN node --version && npm --version 0.7ss => [superset 17/24] WORKDIR /app/superset-frontend 0.0ss => [superset-init 18/24] RUN cp -r /tmp/superset-src/superset-frontend/* . && ls -la 0.5ss => [celery 19/24] RUN npm config set cache /tmp/npm-cache 0.6ss => [celery 20/24] RUN npm ci 948.2ss => => # details. => => # npm WARN deprecated rimraf@3.0.2: Rimraf versions prior to v4 are no longer supported => => # npm WARN deprecated domexception@4.0.0: Use your platform's native DOMException instead => => # npm WARN deprecated rimraf@3.0.2: Rimraf versions prior to v4 are no longer supported u => => # npm WARN deprecated rimraf@3.0.2: Rimraf versions prior to v4 are no longer supported => => # npm WARN deprecated glob@8.1.0: Glob versions prior to v9 are no longer supported ^A
10-23
<think>我们需要打包一个Python工程,其中autoResign.py是入口文件。打包的目标是将这个脚本及其依赖项打包成可执行文件,以便在没有Python环境的机器上运行。 考虑到工程中还有其他文件(如证书文件、jar包、配置文件等),我们需要确保这些资源文件也被正确地包含在打包后的程序中。 推荐使用PyInstaller打包,因为它支持跨平台(Windows、Linux、macOS)并且易于使用。 步骤: 1. 安装PyInstaller: `pip install pyinstaller` 2. 编写打包命令,注意处理数据文件(非代码文件)的包含。 3. 由于工程中包含多个资源文件,我们需要使用`--add-data`参数将这些文件添加到打包后的应用中。 假设当前目录结构如下: autoResign.py hap-sign-tool.jar OpenHarmony.p12 OpenHarmonyApplication.pem OpenHarmonyProfileDebug.pem OpenHarmonyProfileRelease.pem README_ZH.md resign.p7b SgnedReleaseProfileTemplate.p7b UnsgnedDebugProfileTemplate.json UnsgnedReleasedProfileTemplate.json 命令.txt 以及可能还有子目录backup_20251031_111921(但备份目录在打包时不需要包含) 我们只需要打包必要的资源文件,备份目录是程序运行时生成的,不需要打包。 打包命令示例: pyinstaller --onefile --add-data "hap-sign-tool.jar;." --add-data "OpenHarmony.p12;." ... autoResign.py 但是,如果资源文件很多,手动写会很麻烦,因此可以写一个打包脚本来完成。 另外,由于命令行参数长度限制,我们可以使用.spec文件来配置打包。 以下是详细步骤: 步骤1:创建一个打包脚本(例如:build.py)或者直接使用命令行,但这里我们使用.spec文件的方式更合适。 步骤2:生成初始的.spec文件 pyinstaller --onefile autoResign.py 步骤3:修改生成的autoResign.spec文件,在Analysis部分添加datas参数。 例如: datas = [('hap-sign-tool.jar', '.'), ('OpenHarmony.p12', '.'), ...] 步骤4:重新构建 pyinstaller autoResign.spec 但是,为了避免手动修改.spec文件,我们可以编写一个Python脚本来生成.spec文件并执行打包。 下面是一个完整的打包脚本示例,它会自动收集当前目录下需要打包的资源文件(排除.pyc、备份目录等),然后构建可执行文件。 </think>以下是使用PyInstaller打包`autoResign.py`为可执行文件的完整解决方案: ```python """ autoResign 工程打包方案 """ import os import shutil import PyInstaller.__main__ # 1. 安装必要依赖 # pip install pyinstaller # pip install pywin32 (Windows签名需要) # 2. 打包配置 def package_project(): # 工程文件列表(根据实际调整) resource_files = [ "hap-sign-tool.jar", "OpenHarmony.p12", "OpenHarmonyApplication.pem", "OpenHarmonyProfileDebug.pem", "OpenHarmonyProfileRelease.pem", "README_ZH.md", "resign.p7b", "SgnedReleaseProfileTemplate.p7b", "UnsgnedDebugProfileTemplate.json", "UnsgnedReleasedProfileTemplate.json", "命令.txt" ] # 创建临时资源目录 resource_dir = "app_resources" os.makedirs(resource_dir, exist_ok=True) # 复制资源文件到临时目录 for file in resource_files: if os.path.exists(file): shutil.copy(file, resource_dir) else: print(f"⚠️ 警告:文件不存在 - {file}") # PyInstaller配置选项 pyinstaller_args = [ "autoResign.py", # 主程序入口 "--onefile", # 打包为单个可执行文件 "--name=AutoResign", # 生成的可执行文件名 "--add-data", f"{resource_dir}{os.pathsep}.", # 包含资源目录 "--icon=app_icon.ico", # 图标文件(可选) "--console", # 显示控制台窗口 # "--noconsole", # 无控制台版本(GUI应用) "--clean", # 清理临时文件 "--distpath=dist" # 输出目录 ] # 添加Windows签名支持(可选) if os.name == "nt": pyinstaller_args.extend([ "--uac-admin", # 请求管理员权限 "--version-file=version_info.txt" # 版本信息文件 ]) # 3. 执行打包命令 print("🚀 开始打包工程...") PyInstaller.__main__.run(pyinstaller_args) # 4. 清理临时文件 print("🧹 清理临时文件...") shutil.rmtree("build", ignore_errors=True) shutil.rmtree(resource_dir, ignore_errors=True) os.remove("AutoResign.spec") print("✅ 打包完成!可执行文件位于 dist/AutoResign.exe") # 5. 版本信息文件(version_info.txt)示例内容 """ VSVersionInfo( ffi=FixedFileInfo( filevers=(1, 0, 3, 0), prodvers=(1, 0, 0, 0), mask=0x3f, flags=0x0, OS=0x40004, fileType=0x1, subtype=0x0, date=(0, 0) ), kids=[ StringFileInfo( [ StringTable( u'040904b0', [StringStruct(u'CompanyName', u'Your Company'), StringStruct(u'FileDescription', u'Auto Resign Tool'), StringStruct(u'FileVersion', u'1.0.3'), StringStruct(u'InternalName', u'AutoResign'), StringStruct(u'LegalCopyright', u'© 2025 Your Company'), StringStruct(u'OriginalFilename', u'AutoResign.exe'), StringStruct(u'ProductName', u'Auto Resigner'), StringStruct(u'ProductVersion', u'1.0.0')]) ]), VarFileInfo([VarStruct(u'Translation', [1033, 1200])]) ] ) """ if __name__ == "__main__": package_project() ``` ### 打包步骤详解: #### 1. 准备工作 ```bash # 安装必要工具 pip install pyinstaller pip install pywin32 # Windows签名需要 # 创建虚拟环境(推荐) python -m venv venv venv\Scripts\activate ``` #### 2. 配置文件结构 确保工程包含: - `autoResign.py`(主程序) - 所有依赖的资源文件 - `app_icon.ico`(可选图标) - `version_info.txt`(Windows版本信息) #### 3. 执行打包 运行上述脚本: ```bash python package.py ``` #### 4. 输出结果 - 可执行文件:`dist/AutoResign.exe` - 所有资源文件会嵌入EXE中 ### 高级打包选项: #### 1. 添加数字签名(Windows) ```python # 在package_project()函数后添加 def sign_executable(): """使用signtool签名Windows可执行文件""" exe_path = "dist/AutoResign.exe" if not os.path.exists(exe_path): print("❌ 可执行文件不存在") return sign_command = ( 'signtool sign /t http://timestamp.digicert.com ' '/f "certificate.pfx" ' '/p "your_password" ' f'"{exe_path}"' ) print("🔏 正在签名可执行文件...") os.system(sign_command) print("✅ 签名完成") ``` #### 2. 创建安装包 使用Inno Setup创建Windows安装包: ```innoscript ; setup.iss [Setup] AppName=Auto Resigner AppVersion=1.0.3 DefaultDirName={pf}\AutoResigner OutputDir=installer OutputBaseFilename=AutoResigner_Setup [Files] Source: "dist\AutoResign.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "*.p12"; DestDir: "{app}\certificates"; Flags: ignoreversion Source: "*.pem"; DestDir: "{app}\certificates"; Flags: ignoreversion Source: "README_ZH.md"; DestDir: "{app}"; Flags: ignoreversion [Icons] Name: "{commondesktop}\Auto Resigner"; Filename: "{app}\AutoResign.exe" Name: "{commonprograms}\Auto Resigner"; Filename: "{app}\AutoResign.exe" ``` #### 3. 跨平台打包选项 | 平台 | 额外依赖 | 特殊配置 | |------|----------|----------| | Windows | `pywin32` | UAC权限请求 | | macOS | `py2app` | 应用签名 | | Linux | 无 | AppImage封装 | ### 常见问题解决方案: **问题:打包后资源文件找不到** ```python # 在autoResign.py中添加资源路径处理 import sys import os def resource_path(relative_path): """获取资源绝对路径""" if getattr(sys, 'frozen', False): base_path = sys._MEIPASS else: base_path = os.path.abspath(".") return os.path.join(base_path, relative_path) # 使用示例 jar_path = resource_path("hap-sign-tool.jar") ``` **问题:控制台窗口闪烁** - 使用`--noconsole`参数打包 - 添加日志系统替代print **问题:文件防病毒误报** ```bash # 使用UPX压缩(减小体积,减少误报) pip install upx pyinstaller ... --upx-dir="C:\path\to\upx" ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值