引发自:Py的几处不爽 讨论习惯势力在Py 中的思路
::-- ZoomQuiet [2005-06-10 01:34:11]
{{{发件人: flyaflyaa <[email protected]> 回复: [email protected] 收件人: [email protected] 日期: 2005-6-8 下午2:29 主题: [python-chinese] py的几处不爽 }}}揭题
{{{一、
>>> 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]
>>>
这个问题影响不大,可为什么不改掉,很容易产生错误 }}}
讨论
== 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 >>> }}}
回答
{{{发件人: 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。
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 可见并没有不统一的地方,它也能根据需求做出不同的实现,恰好证明这方面是很 好用的。
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知道新值的位置。
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直接处理操作符左侧的对象。 +=操作符好像没办法重写?
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 }}}
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。 }}}