1、python中的变量
python
和java
中的变量本质不一样。
java
中声明变量时要指定变量的数据类型,int、str或某一类,之后虚拟机就会在内存中申请一块空间,空间的大小跟类型相关。通俗的理解就是把变量想象成一个盒子,盒子里能装什么东西,一开始就设定了。
比如a=1
就是将1放到盒子里面。
python
的变量实质是一个指针,指针的大小都是一样的。比如一个指向int类型的指针,指针本身大小是固定的,也不用考虑int本身所占的内存大小,反正是放在内存中。在访问int对象时只需要找到指针即可。
拿a=1
来说,首先去内存中声明一个int类型对象,开辟一块空间用来存储1,然后将a指向1。
a = [1,2,3]
b = a
b.append(4)
print(a) # [1,2,3,4]
这里如果用盒子的思想去理解的话:将列表[1,2,3]
放进一个盒子中,再将a放另一个盒子中,那么修改b之后打印a的话,a就不会发生改变。
a = [1,2,3]
b = a
print(a is b) # True
通过is
也可看到a
和b
是同一个对象,也就是a
指向的对象id
值和b
指向的对象id
值相同。
2、==和is的区别
- is
上边最后说了a = [1,2,3] b = a
这样a和b是同一个对象。那么如果是两个赋值呢?
a = [1,2,3]
b = [1,2,3]
ptint(a is b) # False
print(id(a) == id(b)) #False
从结果来看,此时的a和b是不同的对象。也就是说在使用赋值语句时会重新声明一个对象。
有一个特殊情况如下
a = 1
b = 1
print(a is b) #True
python
内部的intern
机制——遇到相同的一定范围内的小整数时不在生成新的对象,直接指向原来的那个对象。一种内部优化的机制。
小段字符串也是一样的。
a = "abc"
b = "abc"
print(a is b) #True
用is对类进行判断
class People:
pass
person = People()
# isinstance(person,People)
if type(person) is People:
print('Yes') # Yes
因为类本身也是一个对象,而且是全局唯一的对象,person
实际上是指向People
的,所以type(person)
和People
的id是一样的。
- ==
a = [1,2,3]
b = [1,2,3]
ptint(a == b) # True
a是一个list类型的对象,list中实现了一个魔法函数__eq__
,当遇到==时就会调用该函数判断对象的值是否相等。
3、del语句和垃圾回收机制
python
中的垃圾回收算法采用的是引用计数。
先定义a=1
,b=a
,然后1这个对象上就会自动生成一个计数器,a=1
时计数器会加1,b=a
说明b也指向了a,此时计数器再加1,相当于1上面有两个变量指向它。
当我们使用del a
删除对象时,计数器则会减1。当计数器减少到0时,python解释器就会将对象回收(不能一直占用在内存中)。
c++中的删除语句是直接将对象回收,这和python不一样。
举个栗子
a=object()
b=a
del a
print(b) # object object at 0x0000000003D90F0
print(a) # name a is not defined
上面的结果就是b能打印出来,a打印不出来。过程就是将对象a删掉,同时将引用计数器减1。
当python
解释器回收对象时,会去调用对象的__del__
魔法函数。所以当我们做垃圾回收时,希望某些资源在对象被回收时释放,就可以通过重载__del__
函数来实现。
class A:
def __del__(self):
pass
4、关于传入列表的一下注意事项
第一种情况
def add(a,b):
a+=b
return a
if __name__ == "__main__":
a = 1
b = 2
c=add(a,b)
print(c) # 3
print(a,b) # 1 2
第二种情况
def add(a,b):
a+=b
return a
if __name__ == "__main__":
a = [1,2]
b = [3,4]
c=add(a,b)
print(c) # [1,2,3,4]
print(a,b) # [1,2,3,4] [3,4]
发现此时输入的a改变了,因为列表是可变类型,+=符号在运行过程中直接赋值给原前的列表变量a,所以原来的a发生了改变。
第三种情况
def add(a,b):
a+=b
return a
if __name__ == "__main__":
a = (1,2)
b = (3,4)
c=add(a,b)
print(c) # (1,2,3,4)
print(a,b) # (1,2) (3,4)
总结
三种不同类型参数传递进来的时候,只有列表对象对原数据产生了影响。
所以当传递一个对象到函数中,对象如果是list、dict
这类的值可被修改的类型,可能会引起原始数据的改变。