当前位置: 首页 > article >正文

Python Cookbook-4.1 对象拷贝

任务

想拷贝某对象。不过,当你对一个对象赋值,将其作为参数传递,或者作为结果返回时,Python 通常会使用指向原对象的引用,并不是真正的拷贝。

解决方案

Python 标准库的 copy 模块提供了两个函数来创建拷贝。第一个常用的函数叫做 copy,它会返回一个具有同样的内容和属性的对象:

import copy
new_list = copy.copy(existing_list)

某些特殊的时候,你可能会需要对象中的属性和内容被分别地和递归地拷贝,可以使用 deepcopy :

import copy
new_list_of_dicts = copy.deepcopy(existing_list_of_dicts)

讨论

当给一个对象赋值(或者将其作为参数传递,或者作为结果返回时)时,Python(像Java 一样)使用了一个指向原对象的引用,并不是真正的拷贝。其他一些语言则在每次赋值时都进行拷贝操作。Python 从来不为赋值操作进行“隐式”的拷贝:要得到一个拷贝,必须明确地要求,需要的是拷贝,

Python 的行为模式既简单又快速,而且很一致。如果需要拷贝但却不明确地要求,很有可能会遇到麻烦。举个例子:

>>>a = [1,2,3]
>>>b = a
>>>b.append(5)
>>>print a,b
>>>[1,2,3,5] [1,2,3,5]

这里,名字a和b都引用到同样的对象(列表a),所以,无论我们通过哪个名字修改了对象的内容,之后,无论通过哪个名字来查看对象,修改结果都是一样的。这个过程中,并没有一个原始的,未被修改的拷贝。

如果想修改一个对象,但又需要不改动原对象,必须做一个拷贝。如同前面提到的,Python标准库的copy模块提供了两个函数来制作拷贝。一般情况下,可以使用copy.copy,它完成的是对一个对象的浅拷贝——虽然生成了一个新对象,但是对象内部的属性和内容仍然引用原对象,这样的操作速度很快而且节省内存。

如果想从原对象真正地“复制”一个全新的对象,或者想修改的是对象内部的属性和内容,而不是对象本身,那么浅拷贝不能满足你的需求:

>>>list_of_lists = [['a'],[1,2],['z'23]]
>>>copy_lol = copy.copy(lists_of_lists)
>>>copy_lol[1].append('boo')
>>>print list_of_lists, copy_lol
>>>[['a'],[1,2],'boo'],['z',23]]
[['a'],[1,2,'boo'],['z',23]]

这里,名字 list_of_lists 和 copy_lol指向了两个不同的对象(两个列表),所以我们可以分别修改它们而不互相影响。然而,list_of_lists中的元素同样也是 copy_lol的对应元素,所以无论通过哪个名字,一旦我们通过索引修改了元素,以后无论通过哪个名字访问其内容,我们会看到修改已经对两者同时生效了。

所以,如果需要拷贝一些容器对象,还必须递归地拷贝其内部引用的对象(包括所有的元素、属性、元素的元素、元素的属性等),使用copy.deepcopy 这种深拷贝操作,会消耗相当的时间和内存,但如果深拷贝确实是需要的效果,你别无选择。而要实现深拷贝,copy.deepcopy 是唯一可用的方法。

对于普通的浅拷贝,你可能会需要另外一些方法实现同样的功能,当然,假设你知道想拷贝的对象的类型。对于列表L,调用list(L);对于字典 d,调用 dict(d);为了拷贝集合s(Python 2.4中已经引入了内建的类型 set),调用 set(s)。(由于 list、dict 和2.4中的 set 已经是内建的名字了,你无须做任何“准备工作”就可以直接使用。)你现在应该能够领会到这种通用的方法了:为了拷贝一个可被拷贝(copyable)的对象0该对象属于内建的 Python 类型t,可以简单地调用t(o)来创建拷贝。字典还提供了另一个浅拷贝方法:d.copy(),它做的事情和 dict(d)完全一样。不过在这两者之中,我建议你选择 dict(d):这种方式可以和其他类型的拷贝方式统一起来,而且也短一些,少一个字符。

对于任意类型或者类的实例,无论是自己编写的类或者从库中引人的类,一般用copy.copy 就行了。如果是自己编写的类,通常也不值得专门定义一个copy 或者 clone方法,如果想定制自己的类的浅拷贝方式,可以提供一个特殊的__copy__方法(关于实现这个方法的细节请参看6.9节),或者特殊的__getstate__和__setstate__ 方法(参考7.4节中关于这些特殊方法的细节,这些方法也有助于深拷贝和序列化——比如对实例进行 pickling 操作_的实现)。如果想实现自己的类的独有的深拷贝方式,需要提供一个特殊的__deepcopy__方法(参考6.9节)。

注意,没有必要拷贝那些不可改变的对象(字符串、数字、元组等),因为完全不必担心会不经意改动它们。如果尝试进行拷贝操作,仍然会得到原对象,当然这也不会有太大害处,只不过浪费了一些时间和代码。举个例子:

>>>s = 'cat'
>>>t = copy.copy(s)
>>> s is t
True

is 操作符检查两个对象是否相同,而不是相等(is 检查对象是否相同:==操作符则检查两个对象是否相等)。对于不可改变的对象来说,检查是否相同几乎没有什么用处(这里我们只是为了展示对不可改变对象调用 copy.copy 是没意义的,但也是无害的)。对于可改变的对象,检查相同性有时却是至关重要的。举个例子,假设你不确定两个名字a和b是分别指向不同的对象还是引用同一个对象,可以用a is b这样一条简单快速的检查语句来找到答案。当需要确保原对象不被改变时,就可以考虑对原对象进行拷贝操作了。

相关文章:

Python Cookbook-4.1 对象拷贝

任务 想拷贝某对象。不过,当你对一个对象赋值,将其作为参数传递,或者作为结果返回时,Python 通常会使用指向原对象的引用,并不是真正的拷贝。 解决方案 Python 标准库的 copy 模块提供了两个函数来创建拷贝。第一个…...

浅谈时钟启动和Systemlnit函数

时钟是STM32的关键,是整个系统的心脏,时钟如何启动,时钟源如何选择,各个参数如何设置,我们从源码来简单分析一下时钟的启动函数Systemlnit()。 Systemlnit函数简介 我们先来看一下源程序的注释…...

事业单位ABCDE类

1 我刚刚查阅了一下安徽省市直单位报名的表,我这个专业报的岗位大多数是自然科学专技岗。 2 安徽省的岗位大多都限制计算机科学与技术,我这个0854计算机技术能报的岗位十分有限。 而且我没有看到一个岗位只招应届生,显然安徽不保护应届生的…...

Python:函数(一)

python函数相关的知识点 1. 函数定义与调用 定义:使用 def 关键字,后接函数名和参数列表。 def greet(name):"""打印问候语(文档字符串)"""print(f"Hello, {name}!") 调用&#xff1a…...

MySql学习_基础Sql语句

目录 1.数据库相关概念 2.SQL 2.1 SQL通用语法 2.2 SQL分类 2.3 DDL(数据库定义语言) 2.4 DML(数据操作语言) 2.5 DQL(数据查询语言) 2.6 DCL(数据控制语言) 3. 函数 3.1 字…...

Nginx 生产环境安全配置加固

以下是Nginx生产环境安全配置加固的综合方案,结合多个技术实践和行业标准整理: 一、基础安全防护 1‌. 隐藏版本信息‌ 在http或server块添加server_tokens off;,避免暴露Nginx版本号‌。使用headers-more-nginx-module模块彻底移除响应头…...

C#中继承的核心定义‌

1. 继承的核心定义‌ ‌继承‌ 是面向对象编程(OOP)的核心特性之一,允许一个类(称为‌子类/派生类‌)基于另一个类(称为‌父类/基类‌)构建,自动获得父类的成员(字段、属…...

小白学Agent技术[5](Agent框架)

文章目录 Agent框架Single Agent框架BabyAGIAutoGPTHuggingGPTHuggingGPT工作原理说明GPT-EngineerAppAgentOS-Copilot Multi-Agent框架斯坦福虚拟小镇TaskWeaverMetaGPT微软UFOAgentScope现状 常见Agent项目比较概述技术规格和能力实际应用案例开发体验比较ChatChain模式 Agen…...

21.dirsearch:Web 路径扫描工具

一、项目介绍 dirsearch 是一款高效、多线程的 Web 路径扫描工具,专为渗透测试人员和网络安全研究人员设计,用于发现目标网站的隐藏目录、敏感文件及未授权接口。其支持自定义字典、代理配置、请求头伪装等功能,适用于红队渗透、漏洞挖掘及资…...

VSTO(C#)Excel开发4:打印设置

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的,可以在任何平台上使用。 源码指引:github源…...

设计模式Python版 模板方法模式(上)

文章目录 前言一、模板方法模式二、模板方法模式示例 前言 GOF设计模式分三大类: 创建型模式:关注对象的创建过程,包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。结构型模式:关注类和对象之间…...

源IP泄露后如何涅槃重生?高可用架构与自动化防御体系设计

一、架构层解决方案 1. 高防代理架构设计 推荐架构: 用户 → CDN(缓存静态资源) → 高防IP(流量清洗) → 源站集群(真实IP隐藏) ↑ Web应用防火墙(WAF) 实施要点&a…...

transformer bert 多头自注意力

输入的(a1,a2,a3,a4)是最终嵌入,是一个(512,768)的矩阵;而a1是一个token,尺寸是768 a1通过wq权重矩阵,经过全连接变换得到查询向量q1;a2通过Wk权重矩阵得到键向量k2;q和k点乘就是值…...

python-leetcode-定长子串中元音的最大数目

1456. 定长子串中元音的最大数目 - 力扣(LeetCode) 可以使用 滑动窗口 方法来解决这个问题。步骤如下: 初始化:计算前 k 个字符中元音字母的个数,作为初始窗口的值。滑动窗口:遍历字符串,每次右…...

Spring Boot + MyBatis-Plus 项目目录结构

以下是一个标准的 Spring Boot MyBatis-Plus 项目目录结构及文件命名规范,包含每个目录和文件的作用说明,适用于中大型项目开发: 项目根目录结构 src/ ├── main/ │ ├── java/ # Java 源代码 │ │ └── com/…...

Python之变量及简单的数据类型

本文来源于《Python从入门到实践》,自己整理以供工作参考 基本内容 print("Hello Python World!")message "Hello Python world!" print(message)message "Helllo Python Crash Course world!" print(message)name "ada lov…...

力扣 Hot 100 刷题记录 - 翻转二叉树

力扣 Hot 100 刷题记录 - 翻转二叉树 题目描述 翻转二叉树 是力扣 Hot 100 中的一道经典题目,题目要求如下: 给你一棵二叉树的根节点 root,翻转这棵二叉树,并返回其根节点。 示例 1: 输入:root [4,2,7…...

力扣215.数组中的第K个最大元素--堆排序法(java)

为了找到数组中第K个最大的元素,我们可以使用堆排序的方法。堆排序的核心是构建一个最大堆,并通过多次交换堆顶元素来找到前K个最大的元素。具体步骤如下: 方法思路 构建最大堆:将输入数组转换为最大堆,使得每个父节…...

MySQL增删改查操作 -- CRUD

个人主页:顾漂亮 目录 1.CRUD简介 2.Create新增 使用示例: 注意点: 3.Retrieve检索 使用示例: 注意点: 4.where条件查询 前置知识:-- 运算符 比较运算符 使用示例: 注意点&#xf…...

【算法day9】回文数-给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。

回文数 给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。 回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。 例如,121 是回文&#…...

RSA混合加密RSA混合加密

RSA混合加密是一种结合非对称加密(RSA)和对称加密(AES)的技术,通过两者的优势互补,实现高效且安全的数据传输。以下是详细解释和示例: RSA混合加密的核心原理 非对称加密(RSA&#x…...

蛋白质功能预测论文阅读记录2025(DPFunc、ProtCLIP)

前言 最近研究到瓶颈了,怎么优化都提升不了,遂开始看点最新的论文。 DPFunc 2025.1.2 Nature Communication 中南大学 论文地址:DPFunc: accurately predicting protein function via deep learning with domain-guided structure inform…...

Linux网络套接字编程——UDP服务器

Linux网络套接字编程——创建并绑定-CSDN博客 前面已经介绍了网络套接字的创建和绑定,这篇文章会通过UDP套接字实现一个UDP服务器。 先介绍将使用的接口。 recvfrom ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr,…...

主流向量数据库对比

在 AI 的 RAG(检索增强生成)研发领域,向量数据库是存储和查询向量嵌入的核心工具,用于支持高效的语义搜索和信息检索。向量嵌入是文本或其他非结构化数据的数值表示,RAG 系统通过这些嵌入从知识库中检索相关信息&#…...

54.HarmonyOS NEXT 登录模块开发教程(八):测试与调试技巧

温馨提示:本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦! HarmonyOS NEXT 登录模块开发教程(八):测试与调试技巧 文章目录 HarmonyOS NEXT 登录模块开发教程(…...

Vue3中 ref 与 reactive区别

ref 用途: ref 通常用于创建一个响应式的基本类型数据(如 string、number、boolean 等),但它也可以用于对象或数组 返回值: ref 返回一个带有 .value 属性的对象,访问或修改数据需要通过 .value 进行 使用场景: …...

结构型——装饰器模式

装饰器模式 装饰器是指能动态地为对象添加额外的功能的一种结构型设计模式。 特点 不修改原有代码的情况下,动态地扩展一个对象的功能。支持多个装饰器叠加使用透明性,装饰后的对象与原对象保持一致,客户端无需感知装饰过程 结构模式与实…...

在Simulink中将Excel数据导入可变负载模块的方法介绍

文章目录 数据准备与格式要求Excel数据格式MATLAB预处理数据导入方法使用From Spreadsheet模块(直接导入Excel)通过MATLAB工作区中转(From Workspace模块)使用1-D Lookup Table模块(非线性负载映射)Signal Builder模块(变载工况导入)可变负载模块配置注意事项与调试在S…...

分布式事务的产生背景及理论指导

分布式事务的产生背景 在现代互联网和企业级系统架构中,随着业务需求的增长,单体架构逐渐向微服务架构、分布式架构演进。传统单体架构下,事务管理相对简单,可以依赖数据库的本地事务(如 MySQL 的 ACID 事务&#xff…...

动手学强化学习-记录

3.5 蒙特卡洛方法 统计每一个状态s出现的总次数和总回报,用大数定律,总回报/总次数≈状态s的期望回报 第4章 动态规划算法 策略迭代中的策略评估使用贝尔曼期望方程来得到一个策略的状态价值函数,这是一个动 态规划的过程;而价值迭代直接使用贝尔曼最…...