作者:taowen
python中的name binding是非常好玩的,有意思。
大家还不知道什么叫name binding吧,就是假如你叫 “超人”, 然后超人就绑定到了你这个对象上,这个就是name binding了。
比如
这个的意思就是把a 绑定到了对象 1 上面。而a的类型就是number了。
再看一个例子
a也绑定到了对象[1,2,3]上面。可以这么理解[1,2,3]是一个对象存在于内存之中,而a也是一个对象,不过它是一个对象标签一样的对象,任务就是用来引用[1,2,3]。你能够产生[1,2,3]这个对象,用[1,2,3]本身,或者list([1,2,3]),但是对象是一瞬即逝的。其实是一旦过去了你就没有凭据在茫茫内存之中找到[1,2,3]这个对象了。所以要用对象,你就要有一个名字,否则只能一次性使用了,也就是临时对象了。
比如就是这样:
你执行完了len之后,得到3,但是之后再也没法找到那个[1,2,3]了,那个用于len([1,2,3])的[1,2,3]了。你可能还可以用[1,2,3]产生新的对象在内存中,他们毕竟只是一样而不是同一个。
但是你用name来绑定对象就可以做到长期使用了
这里我们又可以看到mylist+[4]其实是另外一个临时对象了,其值应该是[1,2,3,4]。但是由于我们没有用某个名字绑定到mylist+[4]这个临时对象上,你将没法在使用一次之后再次使用。
尝试这样一个观点,name是一个对象,name绑定到的对象也是一个对象。
然后我们来看对于name的操作,对于name的引用大部分是作用到了name绑定的对象身上了:
可以考虑,如果name是一个对象,其本身只是用来指向一个对象。那么其属性应该没有len可言,当然len这个函数操作的其实是mylist指向或者说是绑定到的对象。那么
其实是len直接操作了列表[1,2,3],接收的参数是一个list,而不是一个绑定到了一个list的name。这种对于不同类型的参数表现的其实是不同的行为,一个是取出了绑定的对象求其长度,一个是直接求长度。应该看作函数的多态行为。类似的,对于操作符也有这样的行为:
这里+号对于左右两边都是name,以及一边是真实的list的两种不同情况表现的其实是不同的行为。不用多解释了吧,无非就是取出name绑定的对象,一个是直接操作list而已。那么再来看=号吧。
这下你明白了我的意图吗?打印出来的值是一样的,但是行为是不同的。对于第一个程序。anotherlist 和mylist都是name,而不是真实的list对象。所以对于两个name的赋值行为,其实是把左边的name绑定到右边那么name绑定到的对象上。这样两个name就绑定到了同一个对象上。而加入左边曾经有一个绑定着的对象,那么那个对象如果没有其他name来绑定就无法找到了。
而对于第二个程序,anotherlist被赋给的是一个真实的list,是一个用list构造函数构造出来的临时对象(如果没有被绑定就是临时的了),只不过list构造函数被传入了一个参数,一个绑定了对象的name。这样其实anotherlist和mylist是绑定到了两个不同的对象,但是两个对象有相同的值。
检验的办法是
分别打印的是
[4, 2, 3] [4, 2, 3]
[4, 2, 3] [1, 2, 3]
结果说明了一切。
最后提一点有关于对象回收的问题
前面多次说到了一个对象无法别找到,无法被索引到。其实当一个对象没有name绑定到它的时候,它内部有一个引用计数,这个时候应该是为零了。这个时候将被python的运行环境给回收。因为你找不到它,也就没法用它了,当然就可以安全的被销毁了。而加入是这样
由于一开始的时候是mylist和anotherlist两个都绑定到了[1,2,3]身上,所以mylist的删除(其实是解除绑定,当一个name没有绑定到对象的时候就成为undefined的状态了)并不会导致[1,2,3]这个对象的实际销毁。
希望能够说明一些关于名称绑定上的问题。其实非常简单。
python中的name binding是非常好玩的,有意思。
大家还不知道什么叫name binding吧,就是假如你叫 “超人”, 然后超人就绑定到了你这个对象上,这个就是name binding了。
比如
代码: | [复制到剪贴板] | |
|
这个的意思就是把a 绑定到了对象 1 上面。而a的类型就是number了。
再看一个例子
代码: | [复制到剪贴板] | |
|
a也绑定到了对象[1,2,3]上面。可以这么理解[1,2,3]是一个对象存在于内存之中,而a也是一个对象,不过它是一个对象标签一样的对象,任务就是用来引用[1,2,3]。你能够产生[1,2,3]这个对象,用[1,2,3]本身,或者list([1,2,3]),但是对象是一瞬即逝的。其实是一旦过去了你就没有凭据在茫茫内存之中找到[1,2,3]这个对象了。所以要用对象,你就要有一个名字,否则只能一次性使用了,也就是临时对象了。
比如就是这样:
代码: | [复制到剪贴板] | |
|
你执行完了len之后,得到3,但是之后再也没法找到那个[1,2,3]了,那个用于len([1,2,3])的[1,2,3]了。你可能还可以用[1,2,3]产生新的对象在内存中,他们毕竟只是一样而不是同一个。
但是你用name来绑定对象就可以做到长期使用了
代码: | [复制到剪贴板] | |
|
这里我们又可以看到mylist+[4]其实是另外一个临时对象了,其值应该是[1,2,3,4]。但是由于我们没有用某个名字绑定到mylist+[4]这个临时对象上,你将没法在使用一次之后再次使用。
尝试这样一个观点,name是一个对象,name绑定到的对象也是一个对象。
然后我们来看对于name的操作,对于name的引用大部分是作用到了name绑定的对象身上了:
代码: | [复制到剪贴板] | |
|
可以考虑,如果name是一个对象,其本身只是用来指向一个对象。那么其属性应该没有len可言,当然len这个函数操作的其实是mylist指向或者说是绑定到的对象。那么
代码: | [复制到剪贴板] | |
|
其实是len直接操作了列表[1,2,3],接收的参数是一个list,而不是一个绑定到了一个list的name。这种对于不同类型的参数表现的其实是不同的行为,一个是取出了绑定的对象求其长度,一个是直接求长度。应该看作函数的多态行为。类似的,对于操作符也有这样的行为:
代码: | [复制到剪贴板] | |
|
这里+号对于左右两边都是name,以及一边是真实的list的两种不同情况表现的其实是不同的行为。不用多解释了吧,无非就是取出name绑定的对象,一个是直接操作list而已。那么再来看=号吧。
代码: | [复制到剪贴板] | |
|
代码: | [复制到剪贴板] | |
|
这下你明白了我的意图吗?打印出来的值是一样的,但是行为是不同的。对于第一个程序。anotherlist 和mylist都是name,而不是真实的list对象。所以对于两个name的赋值行为,其实是把左边的name绑定到右边那么name绑定到的对象上。这样两个name就绑定到了同一个对象上。而加入左边曾经有一个绑定着的对象,那么那个对象如果没有其他name来绑定就无法找到了。
而对于第二个程序,anotherlist被赋给的是一个真实的list,是一个用list构造函数构造出来的临时对象(如果没有被绑定就是临时的了),只不过list构造函数被传入了一个参数,一个绑定了对象的name。这样其实anotherlist和mylist是绑定到了两个不同的对象,但是两个对象有相同的值。
检验的办法是
代码: | [复制到剪贴板] | |
|
分别打印的是
[4, 2, 3] [4, 2, 3]
[4, 2, 3] [1, 2, 3]
结果说明了一切。
最后提一点有关于对象回收的问题
前面多次说到了一个对象无法别找到,无法被索引到。其实当一个对象没有name绑定到它的时候,它内部有一个引用计数,这个时候应该是为零了。这个时候将被python的运行环境给回收。因为你找不到它,也就没法用它了,当然就可以安全的被销毁了。而加入是这样
代码: | [复制到剪贴板] | |
|
由于一开始的时候是mylist和anotherlist两个都绑定到了[1,2,3]身上,所以mylist的删除(其实是解除绑定,当一个name没有绑定到对象的时候就成为undefined的状态了)并不会导致[1,2,3]这个对象的实际销毁。
希望能够说明一些关于名称绑定上的问题。其实非常简单。