变量和基本数据类型,深浅拷贝问题
变量
什么是变量
量:衡量/计量/记录某种状态 变:记录下来的某种状态是可以发生变化的
为何要用变量
为了让计算机能够像人一样去识别世间万物,更接近于人的思想 如何识别,就是把事物的特征记录下来=>变量的定义
如何用变量
变量的使用必须遵循:先定义,后引用
定义变量
x=10 name = 'joek' age=18 salary=15k
定义一个变量分为三部分
变量名:变量名是访问到值的唯一方式 赋值符号:将值的内存地址"赋值"给变量名 变量的值:记录状态
变量名的命名规范:
大前提:变量名的命名应该对值有描述性的功能 变量名只能是 字母、数字或下划线的任意组合 变量名的第一个字符不能是数字 关键字不能声明为变量名
变量名的命名风格
驼峰体: OldboyOfAge=73 下划线纯小写式 : oldboy_of_age=73 在python中变量名的命名推荐使用下划线
运行python程序的三个阶段
python3 D:\test.py 先启动python解释器 python解释器将python文件由硬盘读入内存 python解释器解释执行刚刚读入内存的代码,开始识别python语法
引用计数的概念
引用计数:计算值被关联了多少个变量名 引用计算一旦为零就是垃圾,会被python的垃圾回收机制自动清理 引用技术增加 x=10 y=x 引用技术减少 x=10 del x 解除变量名与值10内存地址的绑定关系
变量值具备三个特征(id,tpye,value)
1. id: 变量值的唯一编号,内存地址不同id则不同 2. type:类型 3. value 值
x=10 y=x print(id(x),id(y)) age=10 print(id(age)) print(type(age)) print(age)
is与== : is身份运算:比较的是id是否相等 ==判断值是否相等
x=10 y=x print(id(x),id(y)) print(x is y) #id相等,值一定相等 print(x == y) ''' 1839623936 1839623936 True True '''
值相等id不一定相等(变量补充里会有更加详细的说明)
x=111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 >>> y=111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 >>> id(x) 2181129522824 >>> id(y) 2181129523040 >>> x is y False >>> x == y True
常量(一般约定俗称用大写字母)
BOY_OF_AGE=73 BOY_OF_AGE=74 print(BOY_OF_AGE)
变量的实质
Python变量区别于其他编程语言的申明&赋值方式,采用的是创建&指向的类似于指针的方式实现的。即Python中的变量实际上是对值或者对象的一个指针(简单的说他们是值得一个名字)
对于传统语言,先在内存中申明一个p的变量,然后将1存入变量p所在内存。执行加法操作的时候得到2的结果,将2这个数值再次存入到p所在内存地址中。可见整个执行过程中,变化的是变量p所在内存地址上的值
然而Python实际上是现在执行内存中创建了一个1的对象,并将p指向了它。在执行加法操作的时候,实际上通过加法操作得到了一个2的新对象,并将p指向这个新的对象。可见整个执行过程中,变化的是p指向的内存地址
变量的查找顺序
解析器按照下面的顺序查找一个变量
Local - 本地函数(show_filename)内部,通过任何方式赋值的,而且没有被global关键字声明为全局变量的filename变量; Enclosing - 直接外围空间(上层函数wrapper)的本地作用域,查找filename变量(如果有多层嵌套,则由内而外逐层查找,直至最外层的函数); Global - 全局空间(模块enclosed.py),在模块顶层赋值的filename变量; Builtin - 内置模块(__builtin__)中预定义的变量名中查找filename变量;
在任何一层先找到了符合要求的变量,则不再向更外层查找。如果直到Builtin层仍然没有找到符合要求的变量,则抛出NameError异常。这就是变量名解析的:LEGB法则
变量补充
小整数对象池
整数在程序中的使用非常广泛,Python为了优化速度,使用了小整数对象池, 避免为整数频繁申请和销毁内存空间。
Python 对小整数的定义是 [-5, 256] 这些整数对象是提前建立好的,不会被垃圾回收。在一个 Python 的程序中,无论这个整数处于LEGB中的哪个位置,
所有位于这个范围内的整数使用的都是同一个对象。同理,单个字母也是这样的
ps:不能在pycharm下运行,后面会说为什么 a = -5 b = -5 a is b True a = 256 b = 256 a is b True a = 1000 b = 1000 a is b False
intern机制 处理空格
一个单词的复用机会大,所以创建一次,有空格,创建多次,但是字符串长度大于20,就不是创建一次了
a = "abc" b = "abc" a is b True a = "helloworld" b = "helloworld" a is b True a = "hello world" b = "hello world" a is b False s1 = "abcd" s2 = "abcd" print(s1 is s2) # True s1 = "a" * 20 s2 = "a" * 20 print(s1 is s2) # True s1 = "a" * 21 s2 = "a" * 21 print(s1 is s2) # False s1 = "ab" * 10 s2 = "ab" * 10 print(s1 is s2) # True s1 = "ab" * 11 s2 = "ab" * 11 print(s1 is s2) # False
大整数对象池
说明:终端是每次执行一次,所以每次的大整数都重新创建,而在pycharm中,每次运行是所有代码都加载都内存中,属于一个整体,所以
这个时候会有一个大整数对象池,即处于一个代码块的大整数是同一个对象
#没有在pycharm下运行 a = 1000 b = 1000 a is b False a = -1888 b = -1888 a is b False #在pycharm下运行 c1和d1处于一个代码块,所以相等 而c1.b和c2.b分别有自己的代码块,所以不相等。 c1 = 1000 d1 = 1000 print(c1 is d1) # True class C1(object): a = 100 b = 100 c = 1000 d = 1000 class C2(object): a = 100 b = 1000 print(C1.a is C1.b) # True print(C1.a is C2.a) # True print(C1.c is C1.d) # True print(C1.b is C2.b) # False
数据类型
什么是数据类型
变量值即我们存放的数据,数据类型及变量值的类型
变量值为何要区分类型
因为变量值使用记录现实世界中事物的特征,针对不同的特征就应该用不同类型的值去标识
整型int: 年龄\身份证号\电话号码\等级
age=18
print(id(age),type(age),age)
浮点型float:薪资\身高\体重
salary=3.1 #salary=float(3.1)
print(id(salary),type(salary),salary)
字符串类型str: 名字\家庭住址\单个爱好\性别等等描述性质的特征
定义:在引号(单引号\双引号\三引号)内包含一串字符
name1='egon' name2="egon" name3="""egon""" print(type(name1)) print(type(name2)) print(type(name3)) msg='my name is "egon"' print(msg) msg1='hello' msg2='world' res=msg1 + msg2 print(res,type(res)) print(msg1) print('='*100) print(msg2)
列表list: 记录多个值,比如人的多个爱好,一个班级多个学生的性别
定义:在[]内用逗号分隔开多个任意类型的值
l=[1,3.1,'aa',['a','b','c',['aaaa','bbbb']]] print(l) print(l[0]) print(l[2]) print(l[3][1]) print(l[3][3][0])
字典dict: 记录多个key:value值
定义:在{}内用逗号分隔开多个key:value的值,其中value可以是任意数据类型,
而key通常应该是字符串类型
info={ 'name':'egon', 'age':18, 'sex':'male', 'level':10, 'hobbies':['music','read','dancing'] } #info=dict(...) print(type(info)) print(info['level']) print(info['age']) print(info['hobbies'][1]) emp_info={ name':'egon', 'hobbies':['play','sleep'], 'company_info':{ 'name':'Oldboy', 'type':'education', 'emp_num':40, } } print(emp_info['company_info']['name'])
布尔类型bool: True/False,用来标识条件是否成立
age=18 print(age > 30) print(age < 30)
所有类型的值都自带布尔值: 当数据类型的值为0,None,空时,布尔值为False,除此以外都为True
print(bool(0)) print(bool(None)) print(bool('')) print(bool([])) print(bool({})) print(bool(1)) if None: print('条件成立了11确实大于10的')
深拷贝和浅拷贝问题
什么是深浅拷贝(浅拷贝只拷贝最外层,深拷贝有多少层都拷贝)
深拷贝是对于一个对象所有层次的拷贝(递归)copy.deepcopy
浅拷贝是对于一个对象的顶层拷贝;通俗的理解是:拷贝了引用,并没有拷贝内容.copy.copy 要理解此时引用的意思,不要理解错了
复习:可变类型和不可变类型
不可变类型:整型,长整型,浮点数,复数,布尔,字符串,元组 可变类型:列表,字典
深浅拷贝有什么区别
1、如果用copy.copy、copy.deepcopy对一个全部都是不可变类型的数据进行拷贝,那么它们结果相同,都是引用指向; 2、如果拷贝的是一个拥有不可变类型的数据,即使元组是最顶层,那么deepcopy依然是深拷贝,而copy.copy还是指向 3、基本上只要不是我们自已手动调用的deepcopy方法都是浅拷贝,切片拷贝,字典拷贝都是浅拷贝,而有些内置函数可以生成拷贝(list),属于深拷贝:a = list(range(10))b = list(a)
更加详细的深浅拷贝分析请参考:https://www.cnblogs.com/Eva-J/p/5534037.html