对象可变和不可变&深浅拷贝
1,数据深入了解1
name = "xiaoqiang" age = 24 l = [name,age] #以name为例 print("唯一表示(内存地址)",id(name)) print("数据类型",type(name)) print("数据成员",dir(name)) #数据类型 = 属性(不可调用) +方法(可调用的) print("是否可以调用",callable(name)) print("唯一表示(内存地址)",id(age)) print("数据类型",type(age)) print("数据成员",dir(age)) #数据类型 = 属性(不可调用) +方法(可调用的) print("是否可以调用",callable(age)) print("唯一表示(内存地址)",id(l)) print("数据类型",type(l)) print("数据成员",dir(l)) #数据类型 = 属性(不可调用) +方法(可调用的) print("是否可以调用",callable(l))
运行结果:
唯一表示(内存地址) 1937148160560 数据类型 <class 'str'> 数据成员 ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'removeprefix', 'removesuffix', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill'] 是否可以调用 False 唯一表示(内存地址) 1937142711248 数据类型 <class 'int'> 数据成员 ['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'as_integer_ratio', 'bit_count', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes'] 是否可以调用 False 唯一表示(内存地址) 1937148197184 数据类型 <class 'list'> 数据成员 ['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] 是否可以调用 False
代码:
name = "beifan" new_name = name # 不是创建新变量, 而是把已有变量,传递过来 new_new_name = name # 为什么不支持 打变量的变量名? 有N个变量,打算打印哪个? print(id(name)) print(id(new_name)) print(id(new_new_name)) print("-" * 20) name = "baili" # 创建新的内存 print(id(name)) print(id(new_name)) print(id(new_new_name))# 变量名 和 内存中的数据,不是强关联 # 1. = 赋值号,用来传递变量,而不是创建变量 # 2. "baili" 写在代码中的时候,已经创建好 # 3. 变量名 和 内存中的数据,不是强关联,可以解除关联,断开联系
运行结果:
2087408588272 2087408588272 2087408588272 -------------------- 2087408588336 2087408588272 2087408588272
3. 深拷贝和浅拷贝
copy 复制一个数据对象
代码:
import copy d={ "name":"xiaoqiang", "age":18, "size":[85,85,85] } dd=copy.copy(d) print(d,dd) print(id(d),id(dd))
运行结果:
{'name': 'xiaoqiang', 'age': 18, 'size': [85, 85, 85]} {'name': 'xiaoqiang', 'age': 18, 'size': [85, 85, 85]} 1958350225280 1958350222208
代码:
import copy d = { "name": "shanxi", "age": 18, "size": [89, 89, 89] } dd = copy.copy(d) # 浅拷贝 # dd = copy.deepcopy(d) # 深拷贝 dd['size'].pop() print("复制的字典", id(d), id(dd)) # 创建新的内存 print("字典中的字符串", id(d['name']), id(dd['name'])) # 没有创建新的内存 print("字典中的整数", id(d['age']), id(dd['age'])) # 没有创建新的内存 print("字典中的列表", id(d['size']), id(dd['size'])) # 没有创建新的内存 # 创建新的内存,还是不创建好? # 不创建:省内存,效率高 # 创建:非内存,数据完全隔离 print(d) print(dd)
运行结果:
复制的字典 2056769372032 2056769368960 字典中的字符串 2056772539888 2056772539888 字典中的整数 2056764130064 2056764130064 字典中的列表 2056769689920 2056769689920 {'name': 'shanxi', 'age': 18, 'size': [89, 89]} {'name': 'shanxi', 'age': 18, 'size': [89, 89]}
结论:
浅拷贝:copy.copy 效率高,开销少,但是数据不隔离
为什么修改浅拷贝的数据,没有对其他数据进行影响
深拷贝:copy.deepcopy 效率低,开销单,但是数据完全隔离
所有的变量都是可以深拷贝的吗? 不是
讨论浅拷贝和深拷贝:只针对 可变对象
3,. 图解深浅拷贝
当我们讨论浅拷贝和深拷贝:只针对 可变对象
列表的内存结构
guests = ["Frank", "Claire", "Zoe", True, 42] new_gueste = copy.copy(guests) # 复制列表 new_gueste = copy.deepcopy(guests) # 复制列表 及内容成员
只有列表被复制了一份,列表的中内容,没有被复制: 浅拷贝
只有列表被复制了一份,列表的中内容,也被被复制: 深拷贝
4,小实验
变量的id
name: 1596038932720:173 9B55 68F0
age:1,596,031,173,392:173 9ADF 0310
l :1596036038528: 1739B293F80
name(字符串): 1596038932976:1739B5569F0
l (列表):1596036038528 :1739B293F80
观察到了什么?
1. 内置函数id,返回变量的内存地址 (10进制)
2. 变量在发生变化时,id是否发生变化?
内存地址没有变,内存中值变了 (对原内存就地完成修改)
内存地址变了,内存中值也变了 (没有对内存进行修改,而是在新的内存中放置新的值)
对于数据对接,是否支持在原内存进行修改,可以分为:
可变对象:列表、字典、集合
不可变对象:数字、字符串、元组
为什么字典要求不可变对象作为key?
字典是K-V结构,根据K找到V,如果K偷偷变化,就会找错V
知识
Python内存什么时候销毁:
gc(垃圾回收)机制自动完成内存回收(垃圾数据的销毁)
小题:
小强的成绩如下:
小强 = { "语文": 70, "数学": 65, "英语": 66, "生物": 69, "政治": 78, "跳远": [1.2, 1.3, 1.2] }
大强的语文成绩比小强高20,跳远成绩最后一次是1.5,其他成绩与小强一样
强强的语文成绩比小强高10,其他成绩与小强一样
使用少的代码完成数据处理,使得下面的代码可以同时打印三个人的成绩
print(小强,大强, 强强)
有字符串 a = “aabcdabcd”,写代码计算a出现的次数?
a="aabcdabcd" print(a.count("a"))
运行结果:
3