引发自:Py的几处不爽 讨论习惯势力在Py 中的思路
::-- ZoomQuiet [2005-06-10 01:34:11]
发件人: flyaflyaa <[email protected]> 回复: [email protected] 收件人: [email protected] 日期: 2005-6-8 下午2:29 主题: [python-chinese] py的几处不爽
1. 揭题
一、 >>> a = range(10) >>> a [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> for i in a: i += 1 >>> a [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 如果a中元素是数,用for就不能改变a中元素,只能用filter,map,reduce作复杂 处理了,如果a中元素是list,就可以。不统一。 二、 a = "abccdd" a[0] = 'c" 出错,想改a中的一个元素就要再生成一个新的string,这多慢 三、 函数默认参数是list的话,每次调用都用同一个list,会发生错误。 >>> def foo( a = []): a.append(10) print a >>> foo() [10] >>> foo() [10, 10] >>> 这个问题影响不大,可为什么不改掉,很容易产生错误
2. 讨论
== i++ =
要是有 i++ 就好了..;) >>> i=1 >>> i+=2 >>> i 3 >>> i++ SyntaxError: invalid syntax >>> ++i 3 >>> ++i 3 >>> i+ SyntaxError: invalid syntax >>> +i 3 >>> i++i 6 >>> i++++i 6 >>>
2.1. 回答
发件人: Qiangning Hong <[email protected]> 回复: [email protected] 收件人: [email protected] 日期: 2005-6-9 下午3:37 主题: Re: [python-chinese] py的几处不爽
lyaflyaa wrote: > 一、 >>>> a = range(10) >>>> a > [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>>> for i in a: > i += 1 >>>> a > [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] > 如果a中元素是数,用for就不能改变a中元素,只能用filter,map,reduce作复杂 > 处理了,如果a中元素是list,就可以。不统一。 这是因为你没有理解+=操作符和名字绑定的概念。 当i是数字时:i += 1 --> i = i + 1, 这是对"i"这个名字进行重新绑定。 当i是list时:i += [1] --> i.extend([1]),调用的是i的方法,可以改变i的值。 你如果用i = i + [1]就都不会修改a的值了。 > 二、 > a = "abccdd" > a[0] = 'c" > 出错,想改a中的一个元素就要再生成一个新的string,这多慢 string都是immutable的,不然不能作为dict的key。 如果你不能一次创建string,请先使用list,把要改的东西都改好了,再使用join 生成string。 如果你一定想要mutable string,请仔细阅读:help(UserString.MutableString) google python mutable string,你会得到更多资料。 > 三、 > 函数默认参数是list的话,每次调用都用同一个list,会发生错误。 >>>> def foo( a = []): > a.append(10) > print a >>>> foo() > [10] >>>> foo() > [10, 10] >>>> > 这个问题影响不大,可为什么不改掉,很容易产生错误 默认参数是在定义函数时而不是在调用时创建的。这是feature不是bug。
2.1.1. const行为
发件人: cpunion <[email protected]> 回复: [email protected] 收件人: [email protected] 日期: 2005-6-9 下午4:12 主题: Re: [python-chinese] py的几处不爽
python把一些基本类型(包括string)都实现为const,模拟出const行为,即自身值 不变,每个操作都会生成一个新对象。 它并没有什么不统一,恰恰相反,它非常统一,遍历时确实返回了元素的引用,整 数值没有改变的原因是,整数的add操作没有改变它自身,而是返回另一个对象, 可以写一个非常简单的模拟: >>> class Integer: def __init__ (self, value): self.value = value def __add__ (self, value): self.value += value return self def getValue (self): return self.value >>> class ConstInteger: def __init__ (self, value): self.value = value def __add__ (self, value): return ConstInteger (self.value + value) def getValue (self): return self.value >>> a = [Integer(i) for i in range (10)] >>> for i in a: i += 1 >>> for i in a: print i.getValue () 1 2 3 4 5 6 7 8 9 10 >>> b = [ConstInteger(i) for i in range (10)] >>> for i in b: i += 1 >>> for i in b: print i.getValue () 0 1 2 3 4 5 6 7 8 9 可见并没有不统一的地方,它也能根据需求做出不同的实现,恰好证明这方面是很 好用的。
2.1.2. add行为
发件人: flyaflyaa <[email protected]> 回复: [email protected] 收件人: [email protected] 日期: 2005-6-8 下午6:07 主题: Re: [python-chinese] py的几处不爽
有些明白了,所有整数运算都产生新值,包括付值运算: >>> a = 10 >>> b = a >>> id(a), id(b) (8017228, 8017228) >>> a = 20 >>> id(a), id(b) (8017108, 8017228) >>> 所以用for虽然改变值了,但值在新的位置,list本身并不知道这个位置。 >>> a = range(10) >>> a [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> for i in range(10): print id(a[i]) 8017348 8017336 8017324 8017312 8017300 8017288 8017276 8017264 8017252 8017240 >>> a[0] = 100 >>> for i in range(10): print id(a[i]) 10214556 8017336 8017324 8017312 8017300 8017288 8017276 8017264 8017252 8017240 >>> 所以只有用a[i],才能使list知道新值的位置。
2.1.2.1. cpunion
发件人: cpunion <[email protected]> 回复: [email protected] 收件人: [email protected] 日期: 2005-6-9 下午6:22
i只是个引用名字,当调用i=...时,它会指向不同的对象,所以i+=1时,它所引用 的对象其实是变化了的。但i是list时,为何处理方式不一样呢(我已经推翻前面 的看法,和帖主看法一样了)? 我查看了一点python源码,+=运算符在内部其实是做了不同处理,对于数字类型 (或其它普遍类型),大概会转换成i = i + ..;对于序列类型,它会并不转换成 i = i + ..而是调用concat直接处理操作符左侧的对象。 +=操作符好像没办法重写?
2.1.2.2. limodou
发件人: limodou <[email protected]> 回复: limodou <[email protected]>, [email protected] 收件人: [email protected] 日期: 2005-6-9 下午7:55
+= 相当于执行了 __iadd__( self, other) 看 Python Reference Manual 中的3.3.7 Emulating numeric types
2.1.2.3. Qiangning Hong
发件人: Qiangning Hong <[email protected]> 回复: [email protected] 收件人: [email protected] 日期: 2005-6-9 下午8:05
x+=y 会被解析成 x.__iadd__(y),如果x没有__iadd__方法则解析成x = x.__add__(y) list有__iadd__方法,int没有,这就是差别。 重载+=操作符可以通过重载__iadd__方法实现。详细请看Python Reference Manual中3.3.7节:Emulating numeric types。