本小节介绍了python中变量的本质、==和is的区别、还有del语句和垃圾回收、还有在实际工作中尝尝遇到的一个问题参数传递问题。

1.变量本质

静态类型语言是指在编译时变量的数据类型即可确定的语言。

动态类型语言是在运行时确定数据类型的语言。变量使用之前不需要类型声明,通常变量的类型是被赋值的那个值的类型。

强类型语言是一旦变量的类型被确定,就不能转化的语言。实际上所谓的貌似转化,都是通过中间变量来达到,原本的变量的类型肯定是没有变化的。 弱类型语言一个变量的类型是由其应用上下文确定的。比如语言直接支持字符串和整数可以直接用 + 号搞定。

举个例子,python是强类型语言,而javascript是弱类型语言。java是静态语言,python是动态语音。

Python和Java中变量的本质不一样. Java在定义变量的时候, 就已经确定了该变量的数据类型且不可改变. Python的变量实质上是一个指针, 指针本身的大小是固定的, 它可以指向一个int, 也可以指向str或其他任何数据类型. 在Python中查找数据, 只需要找到指针即可找到对应的数据.

int a = 1
a = 'abc'

这种情况在java中会报错,因为指明了变量a数据类型为int,将字符串abc赋值给变量a时,与定义数据类型不符就会抛错。但是这种情况在python中就可以,因为变量是一个指针,他可以指向任何数据类型,可以是函数、类、对象、list、set等等。可以形象的将java中的变量比喻成一个盒子,赋值时,是要向盒子放数据。而python中的变量可以比喻成一个便利贴,可以随意的贴到任何数据上。这也是动态语音的灵活之处。

2.==和is的区别

==是用来判断值是否相等的,is是用来判断id()是否相等的。

a = [1,2,3,4]
b = [1,2,3,4]
c = a

print(id(a))
print(id(b))
print(id(c))
>>> 2252199937144
>>> 2155368239560
>>> 2252199937144

print(a == b)
>>> True
print(a is b)
>>> False
print(a is c)
>>> True


class Person:
    pass

p = Person()

print(id(Person))
print(id(type(p)))

if type(p) is Person:
    print("yes")

上面例子中可以看到,变量a和变量b的值虽然相等,但是id不相等,所以False。变量a和变量c的id相等,所以为True。对于下面Person类来说也一样,类就是全局唯一对象,使用type(p)其实指向的就是全局唯一Person类,所以用is判断也为True,在python中还有一种特殊情况

a = 1
b = 1

print(id(a))
print(id(b))
>>> 2336549327304
>>> 2336549327304


print(a is b)
>>> True

Python出于对性能的考虑,但凡是不可变对象,在同一个代码块中的对象,只有是值相同的对象,就不会重复创建,而是直接引用已经存在的对象。

# tuple不可变对象
a = (1,)
b = (1,)
print(a is b)
>>> True

# list可变对象
a = [1,2]
b = [1,2]
print(a is b)
>>> False

3.del语句和垃圾回收

python采用的是引用计数机制为主,标记-清除和分代收集两种机制为辅的策略

python里每一个东西都是对象,它们的核心就是一个结构体:PyObject

 typedef struct_object {
 int ob_refcnt;
 struct_typeobject *ob_type;
} PyObject;

PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少

#define Py_INCREF(op)   ((op)->ob_refcnt++) //增加计数
#define Py_DECREF(op) \ //减少计数
    if (--(op)->ob_refcnt != 0) \
        ; \
    else \
        __Py_Dealloc((PyObject *)(op))

当引用计数为0时,该对象生命就结束了。

引用计数机制的优点:

引用计数机制的缺点:

4.参数的经典错误

def add(a,b):
    a += b
    return a

a = 1
b = 2
c = add(a,b)
print(a)
print(b)
print(c)
>>> 1
>>> 2
>>> 3

a = (1,2)
b = (3,4)
c = add(a,b)
print(a)
print(b)
print(c)
>>> (1,2)
>>> (3,4)
>>> (1,2,3,4)

a = [1,2]
b = [3,4]
c = add(a,b)
print(a)
print(b)
print(c)
>>> [1,2,3,4]
>>> [3,4]
>>> [1,2,3,4]

上面的例子中,当传递一个list进去的时候,发现变量a的值也发生改变了。这是因为list是一个值可变的参数,在python中,参数传递是引用,并不是拷贝。传递参数为可变数据数据时,需要特别注意,有可能会造成意想不到的结果。

python3.7 进阶

python 一切皆对象 python 魔法函数 python 类和对象 python Mixin python 自定义序列类 python dict python 对象引用、可变性和垃圾回收 python 元类编程