python中变量定义的问题

python中变量定义的问题

在书上看见“所以说 Python 既是 动态类型定义语言 (因为它不使用显示数据类型声明) , 又是 强类型定义语言 (因为一旦一个变量具有一个数据类型, 它实际上就一直是这个类型了) 。”
既然python是强类型定义语言为什么这样的语句可以成立
a=1
a='123'
a已经定义成整数了。为什么还可以定义成字符串?
没看到过具体资料,我觉得可能和variant/boost.any的实现差不多
文章在这里,是《Python 研究(Dive Into Python)》
http://www.woodpecker.org.cn/div ... ring_functions.html
要知道一个对象与变量名的关系。在python中变量名与对象是不同的东西。一般来说,通过赋值语句会生成一个对象,但这个对象一般不能直接使用,需要通过一个引用来使用它,即给它一个名字。也就是等号左边是一个变量名,右边是生成对象的代码,因此在执行这条赋值语句后就存在了两个东西,一个是名字,一个是对象。在Python中把名字与变量关联起来叫绑定。因此在后面你如果继续对同一个变量名赋值的话,其实是实现了对变量名与新对象的重新绑定,在Python中这是允许的,原来绑定的对象如果无人再使用就自动回收,否则就将引用计数减一。而这个对象是无法改变类型了。

因此你上面的a是变量名,后面才是对象的定义。不知道你是否理解。
是不是这样理解

变量名
+---------+
|    a       |
+---------+

变量
+---------+
|    1       |
+---------+
|  '123'    |
+---------+

变量名可以看作指针,指向变量。只不过指向的变量可以是任意类型

这地方可能不太一致。变量名可以理解为指针,但实际上是引用。
引用和指针有什么区别呢?
多个指针也可以指向一个对象的阿。

变量名在python里面就是一个数组,有global和local.
a这个变量如果是local的他在local数组里的index比如是0
那么a=1就是

local[0]=(1这个常量的地址)
所以无论什么时候,你写a=任何值都是可以的。
但是当你写a+'123'的时候,PyNumber_Add函数不支持这种类型的加法,强类型或许就体现在这里。
其实强类型对于解释器来说和弱类型也没有什么区别,关键是这个语言的内涵。
有点道理。
引用是在C++之中引入的,它可以直接返回原对象。而指针而就是一个内存地址,它返回的是一个地址。因此在c++中,使用引用,可以不需要*,但对于指针还是需要*。而python中的用法是不需要有*这个东西,因此叫引用更合适。

QUOTE:
变量名在python里面就是一个数组,有global和local.
a这个变量如果是local的他在local数组里的index比如是0
那么a=1就是

变量名怎么是数组,你的理解只是在global或local可以找到这个变量名而已。而global和local(其实也不是这样写的,应该是globals()或locals(),这是两个函数)中存的是一个字典,不是数组。根据作用域python会从全局变量或局部变量中查找变量名。变量名相当于找到对象的索引。在python中一切都是动态的,因此变量名也会存在上面的字典中。但通过变量名得到的是原对象,而不是变量名。

QUOTE:
local[0]=(1这个常量的地址)
所以无论什么时候,你写a=任何值都是可以的。
但是当你写a+'123'的时候,PyNumber_Add函数不支持这种类型的加法,强类型或许就体现在这里。
其实强类型对于解释器来说和弱类型也没有什么区别,关键是这个语言的内涵。

就象我已经说过了,a=是一个赋值操作,这样会进行对象的绑定。在python中,可以对一个变量名绑定不同的对象,但原对象仍然存在,除非它的引用计数清0,会自动回收。所以a+'123'时,a因为与1这个对象绑定,所以不能与字符串相加。

可以通过下面的方法验证对象的存在。在python中存在list(相当于数组),它是一个可变的对象,即内容是可以变化的。如:
>>> a = []
>>> b = a

那么a,b都指向同样的对象。然后你可以

>>> print id(a), id(b)
32862696 32862696

id()是用来看一个对象的唯一标识的。你看发现这是一个对象。
然后

>>> a=[1]

你认为会如何呢?如果是指针,那么表示上面的对象应该变化了。因此b也应该等于[1]才对。因为对于指针来说a,b的值应该相同,a=[1]应该是修改a所指地址的内容,所以b的内容也应该变化才对,让我们看一下:

>>> print a, b
[1], []

看到并不一样,再打印id看一下:

>>> print id(a), id(b)
32891288 32862696

可以看到a变了,b没有变。所以并不是指针

再仔细体会一下这个引用吧。
a = []
b = a
用c的语法来写
类似这样。
int t1[5]={0,1,2,3,4};
int t2[1]={1};
int *a;
int *b;
a=t1;
b=a;
a=t2;

实质上,a和b都是一个PyObject的指针。a=[],首先用BUILD_LIST建立一个[]空数组,然后将该[]的地址push堆栈中,然后从堆栈中pop出这个指针,用STORE_FAST 0存入到局部变量中数组中下标是0的那个位置上(0表示a),当b=a时,首先LOAD_FAST 0从fastlocals数组中的0位置把一个指针读出来,然后STORE_FAST 1把这个指针写入到fastlocals[1]中也就是b。其实在这里看出,a和b本身都不是对象而仅仅是指向对象的一个指针而已,甚至[]也是表示指针指向的一个list对象。
这里其实很类似c语言,在c中 "abcd" 是字符串,但是严格的说,是指向常量空间中一个字符串的指针,因此,char *a="abcd",表示a的值为那个指针的数值。此外,python里面变量不是对象,变量仅仅是储存地址的容器而已。局部变量的名字存在co_varnames(tuple)中,局部变量的值存在f_localsplus[]中。而全局变量存放在字典 f_globals中,其中变量名是key,变量值是value。所以,在python语言中,变量就是一个储存指针的空间,而我们永远无法在语言中获得这个空间的地址。

也许我对python语言本身结构了解还不深,目前还没有找到有类似于c++中引用的这样的说法。c++中int &b=a这样的引用赋值方式,可以让b成为a的别名,python里有这种机制吗?python语言的确没有指针这个说法,因为python语言也没有地址这个说法。但是python中每一个变量其实都是指针 PyObject *。而python中所有的东西都是PyObject(函数,数字,字符串,tuple,list,map...)所以,只要=号左边是一个变量名(或正确的lvalue),任何赋值操作都是允许的。
回到你的例子,一开始,a=[],b=a那么a和b的值都是一个指向一个[]list的指针。当a=[1]时,a指向了另外一个地址,那么b和a自然就不一样了。id这个函数,实际上就是就是返回这个指针。
再有一个例子
>>> a=[]
>>> b=a
>>> a.append(1)
>>> print a,b
[1] [1]

正由于a和b都是指向那个[]的指针,a.append实际上是先取到a所指向的对象[]的地址,调用这个对象的append方法。 a.append时操作了[]这个对象,因此print b的时候也看到了变化。

还有globals和locals的确是dict,但是由于locals的值在函数以外是没有用的,因此在函数中,locals的值是放在一个fastlocals的数组中的。

楼上的,我想我和你理解的东西是一样的,只不过表达的方式不同而已。