python: python中a+=b与a=a+b有什么区别

本文探讨了Python中a+=b与a=a+b两种表达式的区别,通过实例说明了这两种表达方式在不同数据类型上的行为差异,特别关注列表与字符串的处理。

看到一个比较有意思的问题,就是python中a+=b与a=a+b有什么区别

链接: http://stackoverflow.com/questions/6951792/python-a-b-not-the-same-as-a-a-b

总体上讲,a+=b是改变了a原始的值,而a=a+b是计算出a+b后,a在指向那个值。这个也跟a和b的类型有关。当a和b是int或者string不可改变的时候,二者效果一样。

>>> a=[1,2,3,4] 
>>> b=a 
>>> a+=[5] 
>>> a,b 
([1, 2, 3, 4, 5], [1, 2, 3, 4, 5])#a,b的“地址”一样 
>>> a=[1,2,3,4] 
>>> b=a 
>>> a=a+[5]#a+[5]后有一个新地址,再使a指向这个新地址,因此a不再是以前的a,而b还是以前的那个a//b,所以b不变 
>>> a,b 
([1, 2, 3, 4, 5], [1, 2, 3, 4])

>>> a=[[1],[2]] 
>>> b=[] 
>>> b+=a[0:1]#这句将列表a中第一个元素的“指针”给了b[0],此时a[0]和b[0]是一样的 
>>> a,b 
([[1], [2]], [[1]]) 
>>> b[0][0]='change'#b[0]就相当于取到了a里面的第一个元素,也是一个列表。b[0][0]也就定位到了a[0][0],对应的内容就是1 
>>> a,b 
([['change'], [2]], [['change']])#因此b[0][0]改了,a[0][0],也相应的改了。 
>>> id(b[0][0]);id(a[0][0])#不用说,地址一样 
11534048 
11534048 
>>> id(b[0]);id(a[0]) 
12903888 
12903888 
>>> b[0],a[0] 
(['change'], ['change']) 
>>> b[0]='another'#这里应该是有一块新地址,再让b[0]指向这个新地址。  
>>> a,b 
([['change'], [2]], ['another'])# 因此a中的值没有变
>>> a[0] 
['change'] 
>>> id(b[0]);id(a[0]) #此时,b[0]跟a[0]的地址不一样
13056672 
12903888

>>> a=[1,2]#初始化a,为列表[1,2]
>>> a+='3' #直接+=方式,追加元素”3”
>>> a
[1, 2, '3']
>>> a+=['4'] #追加列表,比上面的‘3’ 多了个[]。
>>> a
[1, 2, '3', '4']#同样能追加成功,怎么感觉有无[]没有区别啊?
>>> a+'5'#当然,直接+字符串,就抛异常了。
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "str") to list

要解释这个问题,看看python里的源码即可。知道+=这个操作实际上是调用了__iadd__方法(可以用此重载操作符,stackoverflow上有这个重载+=的问题).而在__iadd__方法内部,是直接调用了extend()方法,而a.extend(‘3’)和a.extend([‘3’])没有区别吗?表面上看来是没有区别的。

>>> a=[1,2]
>>> a.extend('3')
>>> a
[1, 2, '3']
>>> a.extend(['3'])
>>> a
[1, 2, '3', '3']

而实际上,在extend(arg)方法内部,又去调用了append方法

def extend(self, values):
        for v in values:
            self.append(v)

这样,’3’ 和 [‘3’] 就没区别被append进去了。字符串会被当作数组append进去。

>>> a
[1, 2, '3', '3']
>>> a.extend('abc')
>>> a
[1, 2, '3', '3', 'a', 'b', 'c']
>>> a.extend(['23','ab'])
>>> a
[1, 2, '3', '3', 'a', 'b', 'c', '23', 'ab']

参考文献: http://stackoverflow.com/questions/6951792/python-a-b-not-the-same-as-a-a-b

https://my.oschina.net/sukai/blog/616652

### 异常处理代码执行结果分析 在 Python 中,异常处理机制用于捕获处理程序运行过程中出现的错误,从而避免程序崩溃并提高代码的健壮性。常见的异常处理结构包括 `try`、`except`、`else` `finally` 等关键字。 一个典型的异常处理代码块如下: ```python try: # 可能引发异常的代码 result = 10 / 0 except ZeroDivisionError as e: # 处理特定类型的异常 print(f"捕获到除以零错误: {e}") except Exception as e: # 处理其他类型的异常 print(f"捕获到其他异常: {e}") else: # 如果没有异常发生,执行此部分 print(f"计算结果为: {result}") finally: # 不论是否发生异常,都会执行此部分 print("执行清理操作") ``` #### 执行流程分析 在上述代码中,`try` 块内的表达式 `10 / 0` 会引发一个 `ZeroDivisionError`,该异常会被对应的 `except` 块捕获。此时,程序将跳过 `try` 块中未执行的部分,直接进入匹配的异常处理分支。由于 `ZeroDivisionError` 是 `Exception` 的子类,因此必须将 `ZeroDivisionError` 的捕获放在更通用的 `Exception` 捕获之前,否则将导致语法错误[^1]。 在 `except` 块中,可以访问异常对象 `e`,并通过其获取错误信息。此时,程序不会继续执行 `try` 块中异常之后的代码,而是跳转到 `finally` 块执行资源释放或清理操作。无论是否发生异常,`finally` 块中的代码都会被执行,通常用于关闭文件、网络连接等资源。 若 `try` 块中没有异常发生,则会跳过所有 `except` 块,直接执行 `else` 块中的代码,最后仍然会执行 `finally` 块。 #### 异常传播机制 如果 `try` 块中引发的异常没有被当前的 `except` 块捕获,则会向上层调用栈传播,直到找到合适的异常处理程序,或者导致程序终止。通过这种方式,可以实现多层嵌套的异常处理逻辑,确保异常在合适的上下文中被处理。 #### 自定义异常处理 除了内置的异常类型,Python 还允许开发者定义自定义异常类,通常继承自 `Exception` 类。这使得异常处理更具语义化,便于调试维护。 ```python class CustomError(Exception): pass try: raise CustomError("这是一个自定义异常") except CustomError as e: print(f"捕获到自定义异常: {e}") ``` 通过这种方式,可以将业务逻辑中的错误类型系统级异常分离,提高代码的可读性可维护性。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值