引发自:Py的几处不爽

讨论习惯势力在Py 中的思路

::-- ZoomQuiet [2005-06-10 01:34:11]

{{{发件人: flyaflyaa <[email protected]> 回复: [email protected] 收件人: [email protected] 日期: 2005-6-8 下午2:29 主题: [python-chinese] py的几处不爽 }}}

揭题

{{{一、

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

[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,会发生错误。

[10]

[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。 }}}

NoNicelyPy (last edited 2009-12-25 07:12:31 by localhost)