1
Kilerd 2018-04-22 18:57:15 +08:00
内容太简单。
你指出的数字例外,不过只是 Python 对小整数的内存优化而已。 PS:大神不要喷我。 |
2
kiwi95 2018-04-22 20:21:14 +08:00 via iPhone
“ Python 会将这个变量指向的对象加 2 后,生成一个新的对象,然后再让 i 指向这个新的对象”
像一楼说的,上面这个说法应该是不对的,并不是生成一个新对象,我猜是和 Java 类似的对小型整数有一个优化,提前定义了 128 以下的小整数 |
3
Mistwave 2018-04-22 20:32:22 +08:00 via iPhone
fluent python 有很好的讲解
|
4
di94sh 2018-04-22 20:41:25 +08:00 via Android
额,python 会对小于 256 的整数做池化,你也可以吧任何你想池化的东西池化。
|
5
lihongjie0209 2018-04-22 21:02:55 +08:00
解决这个问题,推荐再参数传递可变对象时,默认值设置为 None,在函数内部对 None 进行判断后再赋予默认值。
def test(b=None): b = b or [] b += [1] print(b) test() # [1] test() # [1] test() # [1] 这个做法也没有问题, 但是更好的办法是: 不要修改参数!!!!! 用的时候复制一份 def test(b=[]): var = list(b) var += [1] print(var) ####################### 上面的是理论部分################################ ####################### 实践部分 ##################################### def test(b=None): b = b or [] b += [1] print(b) 这种函数真的不会出现在实际代码中, 因为这个函数一点用的没有 函数大概分三种: 1. 无副作用的查询函数: getXXX(), queryXXX() 这种函数有个特点 : 他们都有返回值. 2. 有副作用的修改函数: list.sort() 这种函数有个特点: 他们会改变调用者 /参数的状态, 但是没有返回这 3. 混血: 既有返回值又有副作用: 比如你有一个函数: getUser(id), 会返回一个 User, 但是在调用的时候它把 User 的 queryCount 属性改变了 def test(b=None): b = b or [] b += [1] print(b) 这个函数首先没有返回值, 其次所有的状态都发生在函数作用域之内, 你调用完之后所有的状态都被销毁, 所以也没有副作用. 所有在生产环境中如果看到这种函数,请删了吧, 真的除了增加代码量一点用都没有. |
6
simpleapples OP |
7
simpleapples OP @Mistwave effective python 也有很好的讲解
|
8
simpleapples OP @lihongjie0209 感谢指正 更好的办法确实是 copy 一份
|
9
Kilerd 2018-04-23 13:00:41 +08:00
然而实际上 in python, everything is an object. 所以都是传引用。
|
10
Kilerd 2018-04-23 13:02:17 +08:00
如果用 rust 的思想来讲的话,某些内容满足了 Copy Trait, 所以内部修改不影响外部,最直观的表现就是传参前后的变量没有直接关系。
|
11
jmc891205 2018-04-23 15:50:53 +08:00
自增操作符对不可变对象其实是生成一个新的 object 然后修改引用到这个新的 object。
不可变对象和可变对象的自增操作符的行为是完全不同的。 所以我觉得下面这句话不太准确 > 修改传进的可变参数时,会对外部对象产生影响,修改不可变参数时则不会影响。 比如这段: a = [1, 2, 3] print(id(a)) # 1437494204232 def mutable(a): ----print(id(a)) # 1437494204232 ----a = [2, 3, 4] ----print(id(a)) # 1437494207528 mutable(a) print(a) # [1, 2, 3] print(id(a)) # 1437494204232 |
12
simpleapples OP @jmc891205 我理解你第一句话的意思 但是不明白下面那句哪里不太准确 可不可以再详细说一下?
|
13
jmc891205 2018-04-23 16:42:42 +08:00
@simpleapples 你看我给的例子 在函数里修改传进来的可变对象参数 没对外部对象产生影响
|
14
simpleapples OP @jmc891205 嗯 看到了 不过这个不是修改了 而是重新给 a 赋值 修改应该是 a+=[1]或者 a.append(1)
这块字面意思上看确实有点不太准确 谢谢指正 |
15
jmc891205 2018-04-23 17:41:43 +08:00
@simpleapples 所以就回到我第一个回复的第一句话了,对于不可变对象,自增操作符实际上是一个赋值的操作。
因此在讨论 Python 的传参的时候 不应该按可变对象不可变对象来分类 而应该而操作符 /函数调用的类型来分类。 |