发表日期: 2021-04-27 13:36:22 浏览次数:110
杞县网络公司哪家好【杞县企业网站百度SEO推广公司】杞县做网站开发价格、杞县淘宝店铺开店装修设计运营、公司网站制作方案流程改版维护费用、杞县高端企业网站页面制作设计专业公司需要多少钱
杞县是河南省开封市辖县,位于河南省东部,北接开封市兰考县和商丘市民权县,东临商丘市睢县,南至周口市太康县,西到开封市祥符区和通许县。
杞县是“省级历史文化名城”,夏朝时期的杞国曾在这里建都立国长达1000余年 [1] 。是近代著名的豫东革命根据地,豫东战役大量战斗发生于此,是河南13个一类革命老区之一。
杞县素有“中原粮仓”之美称。 [2] 2012年杞县产业集聚区被评为“全省十佳新型工业化产业示范基地”。 [3] 2018年12月13日,入选中国特色农产品优势区名单。 [4]
Python是一种动态类型编程语言,与C/C++等静态类型编程语言不同,Python中的变量没有固定的类型,变量也无需提前声明分配内存空间,因此我们可以给任何变量赋值任何符合Python规范的类型值,比如
交互式Python代码:
>>> var = 88 >>> var = 'hello world'
在C语言中,变量使用前需要提前声明并明确其类型(或声明和赋值可同一条语句执行),以便为其分配内存空间,比如
C代码:
int a; a = 100;
但在C语言中一般不可直接将其他类型值赋值给不同类型的变量(可强制类型转换的除外),例如如下代码就会报错:
C代码:
int a; a = "hello world";
在Python中将字面量或变量对另一个变量进行赋值可以理解为:给内存中的变量实体贴上一个标签。这个标签就是变量标识符。
交互式Python代码:
>>> a = 100 >>> b = a >>> a is b True
上述代码表明变量a
与变量b
是同一个对象,标识符a和标识符b都是内存中变量实体100的一个标签。在C语言中,因为每个变量都有自己的内存空间,变量赋值是将值复制到指定的内存中,因此进行赋值的两个变量只是值相同,但并不表示同一个对象。
C代码:
#include <stdio.h> int a = 100; int b; b = a; if (&a == &b) { printf("yse\n"); } else { printf("no\n"); } // 输出:no
Python中函数的实参和形参之间以及返回值也是进行赋值操作的。
交互式Python代码:
>>> a = 3 >>> b = 5 >>> def func(m, n): print(m is a) print(n is b) r = m + n print('id(r):', id(r)) return r >>> c = func(a, b) True True id(r): 10914624 >>> id(c) 10914624
根据上述代码可知,Python函数调用时形参会被实参进行赋值操作,即在执行c = func(a, b)
时其实相当于在函数内部执行了m = a
和n = b
。那么就会出现一个问题,当实参为可变对象时,在函数内部就存在改变实参的风险。
交互式Python代码:
>>> a = [1, 2] >>> def func(List): List.append(a[0] + a[1]) return List >>> c = func(a) >>> print(c) [1, 2, 3] >>> print(a) [1, 2, 3] >>> id(a) == id(c) True
上述代码中a
为列表类型(可变对象),在函数内部List
添加了一个元素并返回。a
,List
和函数返回后的c
表示同一个对象,这是我们之前讨论过的。现在我们讨论的重点是在函数内部改变了函数的实参,当然在有些情况下,我们正是需要借助这种特性完成某种功能,这种情况我们暂且不讨论。但在实际的工作中,更多的情况是我们不想函数更改实参,针对这种情况我们应该怎样规避实参被更改的风险呢?有三种方法:
下面我就来讨论今天的第二个重点:拷贝。
尽量使用不可变类型作实参
当实参为不可变对象时,函数内部形参的操作不会影响实参。
交互式Python代码:
>>> a = 55 >>> id(a) 10916224 >>> def func(value): print('id(value):', id(value), 'value: ', value) print(value is a) value = 99 print('id(value):', id(value), 'value:', value) print(value is a) >>> func(a) id(value): 10916224 value: 55 True id(value): 10917632 value: 99 False >>> print('id(a):', id(a), 'a:', a) id(a): 10916224 a: 55
上述代码中a
为int类型(不可变类型),作为实参赋值给形参value
,函数在执行value = 99
之前value
与a
表示同一个对象,在执行之后value
与a
表示不同的对象,其实这很好理解就像我们前面讨论的,在执行赋值语句之后value
标识符被“贴”到另一个内存变量实体99上了。
使用拷贝
以上两种都不想用?那就写代码的时候多注意吧
Python中的拷贝分为浅拷贝和深拷贝
浅拷贝
Python中的默认拷贝都是浅拷贝,这里我们就拿列表类型举个栗子,先看看列表有哪些拷贝方法,此处参考Python语言及其应用:
交互式Python代码:
>>> a = [1, 2, 3] >>> b = a.copy() >>> a [1, 2, 3] >>> b [1, 2, 3] >>> b is a False >>> c = list(a) >>> c [1, 2, 3] >>> c is a False >>> d = a[:] >>> d is a False
上述代码中显示出三种列表拷贝方法:
我们也可看到拷贝出来的对象与被拷贝对象不再是同一个对象,这也是拷贝的根本目的。当使用可变对象的拷贝进行函数传参可以避免函数内部修改实参。
交互式Python代码:
>>> a = [1, 2, 3] >>> def func(List): List.append(100) List[0] = 'hello' return List >>> b = func(a.copy()) >>> b ['hello', 2, 3, 100] >>> a [1, 2, 3]
好像一切都很完美,达到了我们的目的。于是我们编写了下面这样的代码:
交互式Python代码:
>>> a = [1, 'hello', 'world', [88, 99], 22] >>> def func(List): List.append('shawn') List[0] = 'simon' List[3][0] = 100 return List >>> b = func(a.copy()) >>> b ['simon', 'hello', 'world', [100, 99], 22, 'shawn'] >>> a [1, 'hello', 'world', [100, 99], 22]
有瑕疵啊,这运行结果和我们想象的不一样,我们想象着变量a
索引为3的元素值仍为[88, 99]
,但输出并不是这样,问题出在了哪里?原因在于我们前面所说的Python中的默认拷贝均为浅拷贝,如果我们想要输出达到我们的预期,则需要深拷贝。
使用列表对象的.copy()
方法
使用list()
转换函数
使用列表分片[:]
深拷贝
深拷贝就是在每个层次都对可变对象进行拷贝,浅拷贝只对最外层可变对象进行拷贝。
我们先来看看赋值的情况即b = a
,如下图所示:
示意图a
与b
指向同一个对象,我们通过代码验证其正确性:
交互式Python代码:
>>> a = [1, 2, [3, 4]] >>> b = a >>> id(b) == id(a) True >>> id(a[0]) == id(b[0]) True >>> id(a[1]) == id(b[1]) True >>> id(a[2]) == id(b[2]) True >>> id(a[2][0]) == id(b[2][0]) True >>> id(a[2][1]) == id(b[2][1]) True
再来看看浅拷贝的情况,先上图:
上图中为b = a[:]
示意图,b
为a
的浅拷贝,浅拷贝会将最外层可变对象进行拷贝,下面进行代码验证:
交互式Python代码:
>>> a = [1, 2, [3, 4]] >>> b = a[:] >>> id(b) == id(a) False >>> id(a[0]) == id(b[0]) True >>> id(a[1]) == id(b[1]) True >>> id(a[2]) == id(b[2]) True >>> id(a[2][0]) == id(b[2][0]) True >>> id(a[2][1]) == id(b[2][1]) True
最后来看看深拷贝,深拷贝我们需要用到copy库的deepcopy,示意图如下:
接下来进行代码验证:
交互式Python代码:
>>> from copy import deepcopy >>> >>> a = [1, 2, [3, 4]] >>> b = deepcopy(a) >>> id(a) == id(b) False >>> id(a[0]) == id(b[0]) True >>> id(a[1]) == id(b[1]) True >>> id(a[2]) == id(b[2]) False >>> id(a[2][0]) == id(b[2][0]) True >>> id(a[2][1]) == id(b[2][1]) True
因此当实参为可变对象且其中含有多层嵌套的可变对象时,如果我们不想因为我们的粗心让函数更改实参,那么我们就应该使用深拷贝,看代码:
交互式Python代码:
>>> a = [1, 2, [3, 4]] >>> def func(List): List.append('hello world') List[0] = 'shawn' List[2][0] = 'simon' List[2][1] = 199 return List >>> from copy import deepcopy >>> b = func(deepcopy(a)) >>> a [1, 2, [3, 4]] >>> b ['shawn', 2, ['simon', 199], 'hello world']
Note: Python中的深拷贝和浅拷贝只是针对可变对象而言,而对于不可变对象无所谓深拷贝还是浅拷贝,因为对于不可变对象两种拷贝和变量之间赋值没什么两样。
交互式Python代码:
>>> from copy import deepcopy >>> >>> a = 'hello world' >>> b = deepcopy(a) >>> c = a >>> id(a) == id(b) == id(c) True
Python中变量之间的赋值,相当于给变量多贴了一个“标签”,或者说给变量起了个别名
深拷贝、浅拷贝是针对可变对象说的,不可变对象无所谓什么拷贝
对于可变对象,深拷贝对每层可变对象都进行拷贝,而浅拷贝只对最外层进行拷贝
当函数实参为可变对象且我们不想函数改变实参本身,应尽量使用深拷贝,尤其在实参中嵌套了可变对象时
杞县网络公司哪家好【杞县企业网站百度SEO推广公司】杞县做网站开发价格、杞县淘宝店铺开店装修设计运营、公司网站制作方案流程改版维护费用、杞县高端企业网站页面制作设计专业公司需要多少钱
备案号: 苏ICP备11067224号
CopyRight © 2011 书生商友信息科技 All Right Reserved
24小时服务热线:400-111-6878 E-MAIL:1120768800@qq.com QQ:1120768800
网址: https://www.768800.com 网站建设:上往建站
关键词: 网站建设| 域名邮箱| 服务器空间| 网站推广| 上往建站| 网站制作| 网站设计| 域名注册| 网络营销| 网站维护|
企业邮箱| 虚拟主机| 网络建站| 网站服务| 网页设计| 网店美工设计| 网站定制| 企业建站| 网站设计制作| 网页制作公司|
400电话办理| 书生商友软件| 葬花网| 调温纤维| 海洋馆运营维护| 北京保安公司| 殡仪馆服务| 殡葬服务| 苏州殡葬一条龙| 朝阳殡葬| 苏州殡葬服务|
欢迎您免费咨询,请填写以下信息,我们收到后会尽快与您联系
服务热线:400-111-6878