变量
什么是变量
量:衡量/计量/记录某种状态 变:记录下来的某种状态是可以发生变化的
为何要用变量
为了让计算机能够像人一样去识别世间万物,更接近于人的思想 如何识别,就是把事物的特征记录下来=>变量的定义
如何用变量
变量的使用必须遵循:先定义,后引用
定义变量
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