Re: [问题] 关于赋值

楼主: ThxThx (洗洗睡)   2019-02-04 12:02:02
关于前一篇大部分都是正确的观念,除了...
※ 引述《germun (ger)》之铭言:
: ※ 引述《nevikw39 (牧)》之铭言:
: : 如题,Python 的变量系统至今对我仍然是个谜。
: : Python 既是动态语言,变量感觉倾向于强型别但又不需要再宣告。因此,直译器到底是怎
: : 么判断型别的?而且,同一个变量名称前后可能指涉不同型别。
: 虽然python没有指标, 但没有指标观念的话很容易落入陷阱
: 没有指标或物件导向观念的话最好先去懂
: 首先python没有变量(variable), 只有`name`
: (我不知怎么翻, 所以以下全称name)
: 用`赋名`形容比较合适, 只是我们有时还是习惯用变量来称呼
: 所谓name的意思, 就是等号左边只是个名称, 将其名称指到右边的物件
: 所有物件的属性定义全都是依右边assign的物件来决定,
: 所以才不需事先宣告, 因为物件在建立时已有它的型态和各种资料
: 等号只是将 name 指到该物件, 或反过来说: 给右边的物件取一个 name
: 例如:
: ==========
: a = 2
: b = 2
: ==========
: 若从C的角度来开, 是将a跟b的值设成2,
: 但从python来看, 任何数字或任何字串本身也都是物件
: 这边是分别将 a 跟 b 指到 `2` 这个int物件
: 所以 id(a) == id(b) 跟 id(a) == id(2) 会是True, 因为都指到同一物件 `2`
==================================
: 这边是分别将 a 跟 b 指到 `2` 这个int物件
: 所以 id(a) == id(b) 跟 id(a) == id(2) 会是True, 因为都指到同一物件 `2`
这边程式码的意义并不是将a跟b指到"同一个"2
对于literal,Python首先会创造一个object,再把名字bind到object上
literal在Python语言里只是一个让你建立一个物件的方式
所以有可能id(a) != id(b) (你可以试一个大于256的数字就知道了)
BUT!!!
为了增进效率,literal可能会有相同的id,例如在这里,当有名字指到`2`时,
CPython就会把他指到固定的`2`物件,所以这里的id会一样
同样的情况也发生在`True`,`False`等常用的物件上
关于哪些是固定的物件是implementation details
==================================
: 接着再一行
: ===========
: b = 4
: ===========
: 正确的解读是将 b `重新指向` 4 这个物件
: : 主要想请教的是 dict 和 list 的部分:
: : # base 读自 json
: : def callback(e):
: : ...
: : data = base
: 从这一行来解读
: base是已存在的name, 已经有其指向的物件 (举例来说是个字串"abc"好了)
: 那么base其实只是个指向"abc"的 name
: 这行的结果就只会是:
: => 新建一个name `data`, 指向`base`所指的物件
: 白话讲就是, base指向谁, 那么data也同样指向谁
: 也就是:
: base -> "abc"
: data -> "abc"
: 两者 "abc" 是同内存位置的同一物件
: 因而你透过 `data[...] = XXX` 去改动的元素内容, 对应的`base[...]`也会改动
==================================
这边用字串来做举例可能不太好:D
因为字串是immutable的,所以技术上来讲没办法改动物件内容
不过"id会一样"这件事是确定的
==================================
: 但你若直接:
: ======
: data = "ddd"
: ======
: 这时就会是将data重新指向一个新物件 "ddd", 而不会改动base的内容
: : data[...] = ...
: : 这样好像会改动到原本 base 的值欸?
: : 还有例如:
: : lst = []
: lst是个物件 `[]`
: : a = [0, 0, 0]
: a也是个物件 `[0, 0, 0]`
: : lst.append(a)
: 把a放入lst
: 此时lst[0] 会指向 a 所指的物件
: id(lst[0]) == id(a) 为 True
: : for i in range(len(a)):
: : a[i] += 1
: a还是同一个list, 内存位置不变, 但里面元素所指的物件都变成1
: 即 a[0], a[1], ... = 1, 1, ...
: 到这时你lst[0]里面已经跟着变成 [1,1,1], 因为是同一个list
: ps. 要注意这跟 `a = [1,1,1]` 是不同行为, 这是重新建新的list
: : lst.append(a)
: 再一次把a放进去,
: 所以lst[0], lst[1]都是同一个list,
: 一改内容两个就一起改了
: : 结果 lst 的值不是 [[0, 0, 0], [1, 1, 1]] ,而是 [[1, 1, 1], [1, 1, 1]] 欸!
: : 所以,当我作 data = base 这个运算时,感觉只是将 data 参考指向 base 这个实体而已
: : ,而我若 lst.append(a) 也只是把 lst 的尾端指向 a。那么,Python 的指派究竟何时是
: : 参考,何时是复制呢?
: 你如果一定要用list的话, 那就一定要先建一个新list
: 例如 b = [], 再把值丢进去
: 或直接复制内容:
: b = a[:]
: 这样的解读相当于:
: b = [a[0], a[1], ....]
: 把a的元素分别取出重新建一个list, 如此a跟b就会是不同list
: 甚至是
: a = a[:] # 重新建一个list `a`, 原本的list a遗失,
: 但这边原本的 a 已经放入`lst`中所以无妨
: 但要注意这边不会出错是因为a[0]本身是指向int物件, 因此不会有问题
: 如果 a[0] 指向的是list这类物件, 也就是你的 a 若是二维以上的list,
: 或其他具有属性的物件, 那又会回到上述状况了
: 如果你要用到2维以上来计算值, 例如矩阵
: 那么用numpy array是比较容易
: 不过numpy array跟list又有微妙不同之处, 那又是另一回事了
作者: XperiaZ6C (真●安卓轻旗舰)   2019-02-04 12:03:00
作者: germun (ger)   2019-02-04 12:43:00
随便举个例所以没注意到string的操作细节 谢谢指正
作者: HenryLiKing (HenryLiKing)   2019-02-04 15:57:00
钓出超多大神!
作者: pxycho (trolltrolltroll)   2019-02-12 15:03:00
推这篇正解

Links booklink

Contact Us: admin [ a t ] ucptt.com