python中有指针吗_Python中的指针——到底指什么(⼀)指针是C和C++系语⾔的重要概念,其本质是保存另⼀个变量内存地址的变量(Pointers are variables that hold the memory address of another variable.)。某些情况下,使⽤指针可以提⾼代码的效率。但是,指针也往往会对初学者造成困扰,即使是⽼⼿,也经常会出现内存管理的问题。
象Java、Python之类的语⾔并没有明确的指针的概念。但Python中如果需要使⽤类似指针⾏为的时候,可以模拟出指针的效果,同时⼜不会陷⼊内存管理的噩梦。
Python中为什么没有指针
看起来指针似乎违背了Python设计之禅(Zen of Python)。指针会带来隐含的修改,对初学者来说显得⽐较复杂,⽽且也为访问⾮预期内存块之类的危险操作提供了⼿段。Python倾向于对⽤户屏蔽类似内存管理之类的实现细节,更注重语⾔的实⽤性,甚⾄都不太关⼼执⾏速度。
Python中的对象
在Python中,⼀切都是对象。可以通过提供的内置函数isinstance()进⾏验证:
>>> isinstance(1, object)
True
>>> isinstance(str, object)
True
>>> isinstance(list(), object)
True
>>> def func():
pass
>>> isinstance(func, object)
True
由此可见,Python中⽆论基本类型、类、类实例、⾃定义函数等都是对象。对象⾄少由三部分数据组成:
引⽤计数(Reference Count)
对象类型(Type)
对象值(Value)
其中引⽤计数⽤来进⾏内存管理;对象类型⽤于在Python本⾝的实现层(CPython)保证运⾏期的类型安全;对象值才是对象的真实数据。
要想拨开Python指针的层层迷雾,⾸先需要了解Python中的两类对象。
不可变对象与可变对象
顾名思义,不可变对象(Immutable Object)就是值不能改变的对象,象int、bool、float、str、tuple等都是不可变对象,相反,list、set、directory等都是可变对象(Mutable Object)。可以使⽤id()函数(返回对象的内存地址)、is(两个对象具有同⼀个内存地址时返回True,否则返回False)对此进⾏验证:
>>> x = 5
>>> id(x)
8791652754384
>>> x = x + 1
>>> id(x)
8791652754416
>>> s = 'Python'
>>> id(s)
31016864
>>> s += ' test'
>>> id(s)
52447280
>>> s[0] = 'p'
java python是什么意思Traceback (most recent call last):
File "", line 1, in
s[0]='p'
TypeError: 'str' object does not support item assignment
>>> lt = [1, 2, 3]
>>> id(lt)
52176968
>>> lt.append(4)
>>> id(lt)
52176968
>>> lt[0] = 5
>>> id(lt)
52176968
对整形对象x和字符串对象s进⾏操作后,得到了另⼀个对象(id函数返回了另⼀个值,说明对象的内存地址变了),对s[0]赋值时,得到TypeError,说明str对象的元素是不能进⾏赋值的;对list对象lt操作后,得到的还是原来的对象lt。这就说明x、s是不可变对象,lt是可变对象。
深⼊理解变量
Python中的“变量”与C和C++中的变量是截然不同的。甚⾄在Python中就不应该叫做变量(variables),⽽应该叫做名称(names)。听起来很怪异,但通常情况下把Python中的名称认为是变量也没关系,重要的是要理解它们的不同之处。
在C语⾔中,定义⼀个整形变量x:
int x = 2505;
挺简单的⼀句话,其背后发⽣了什么?
申请⼀个⾜够存储整型值的内存空间;
将2505赋值给该内存地址;
将x指向该值。
内存⽰意图如右图所⽰:
要修改x的值,只需要执⾏:
x = 2504;
该语句将新值2504赋给了变量x,覆盖了原值2505,更新后的内存显⽰了新值:
需要注意的是x的地址没有发⽣变化,仅是值变化了。这意味着x是内存地址,⽽不仅仅是个名字。 可以从另⼀个⾓度思考:x拥有⼀个内存地址(容器),该地址可以存储⼀个整形数,当将值赋给x时,相当于把这个值放进了x所拥有的内存地址。执⾏:
int y = x;
代码创建了⼀个新的容器(占⽤⼀段内存),并把x的值复制到该容器中,内存看起来是这样的:
虽然x的值复制给了y,但y拥有了⼀段新的内存,改写y值的时候对x没有影响。
再来看看Python中等价的代码:
x = 2505
除了不⽤声明x的类型外,和C代码没有区别。同样,代码的背后会执⾏以下操作:
创建⼀个PyObject对象(不同于Python中的对象,是CPython特有的Python中所有对象的基本结构。PyObject是C结构体,⽆法直接访问typecode和refcount等,不过通过fcount()可以获取⼀些内部信息);
将PyObject对象的类型设置为整形;
将PyObject对象的值设置为2505;
创建⼀个称为x的名称;
将x指向新创建的PyObject对象;
将PyObject对象的引⽤计数加1。
内存⽰意如下:
与C语⾔中变量x拥有存储2505的内存块不同,Python中新创建的PyObject拥有这块内存,但是名称x并不拥有任何⼀块内存。
要将x的值修改为2504,执⾏:
x = 2504
这⾏代码会执⾏以下操作:
创建⼀个新的PyObject对象;
将新PyObject对象的类型设置为整形;
将新PyObject对象的值设置为2504;
将x指向新创建的PyObject对象;
将新PyObject对象的引⽤计数加1;
将旧PyObject对象的引⽤计数减1。
现在的内存⽰意图如下:
上图表明x指向⼀个对象的引⽤,⽽不拥有内存空间。x=2338语句不是⼀个赋值语句,⽽是将x绑定到⼀个引⽤。⽽且,旧的对象在内存中的引⽤计数为0,将等待被垃圾回收机制回收。
象C代码⼀样,将x赋值给⼀个新的名称y:
y = x
内存看起来就会是这个样⼦的:
并没有创建新的对象,只是将新名称y指向了同⼀个对象,可以通过 y is x 返回True确定x和y是同⼀个对象。同样,y也是不可变对象,如果对y进⾏操作,如y += 1,那么y就会绑定到⼀个新的对象,这时y is x就会返回False。
深刻理解Python中的对象是了解指针的重要基础,下篇⽂章中将会详细说明Python指针的具体内容。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论